Multiple SQL SELECT WHERE with INTERSECT, placeholder value

ぐ巨炮叔叔 提交于 2020-01-24 22:08:21

问题


I'm using SQL Server and am trying to do the following:

SELECT dword FROM Details WHERE dskey = '51a'
INTERSECT
SELECT dword FROM Details WHERE dskey = '52b'
INTERSECT
SELECT dword FROM Details WHERE dskey = '53i'
INTERSECT
SELECT dword FROM Details WHERE dskey = '54d'
INTERSECT
SELECT dword FROM Details WHERE dskey = '55e';

This works fine. However, I need to build a generic SELECT like:

SELECT dword FROM Details WHERE dskey = value1
INTERSECT
SELECT dword FROM Details WHERE dskey = value2
INTERSECT
SELECT dword FROM Details WHERE dskey = value3
INTERSECT
SELECT dword FROM Details WHERE dskey = value4
INTERSECT
SELECT dword FROM Details WHERE dskey = value5;

However, at any given execution I probably won't have all five key values. I need someway to have dummy key values that won't interfere with he INTERSECTs.

For example, say I have only 1 value, the remaining 4 are null. But the INTERSECT doesn't (correctly) work.

Is there anyway to have dummy values that won't interfere with the INTERSECTS.

I hate to have to do nested ifs where if I only have one value I only perform one SELECT. If I have two values then I have two SELECTS with an intervening INTERSECT and so on.

Here is what this is all about:

Say I have a 5 character word, I want to be able to do a SELECT WHERE to return a list of say all 5 character words that have 'i' in the third position. Easy enough. Then I may want to SELECT where the third position is 'i' and fifth is 'e'. This resembles "Wheel of Fortune". I may have all five values a-b-i-d-e so the returned set only should be abide. Hence, it would be nice to have one set of 5 SELECTS with four intervening INTERSECTS that this construct could handle 1 to 5 values.

I've tried NULL values and that clearly doesn't work as it shouldn't.


回答1:


You can also construct the query as:

SELECT dword
FROM Details
WHERE dskey IN (value1, value2, value3, value4, value5)
GROUP BY dword
HAVING COUNT(DISTINCT dskey) = 5;

You still need to replace the IN list and the number 5. You could write this using explicit parameters:

WITH vals as (
      SELECT v.val
      FROM (VALUES (@value1), (@value2), (@value3), (@value4), (@value5)) v(val)
    )
SELECT dword
FROM Details d JOIN
     vals
     ON d.dskey = vals.val
GROUP BY dword
HAVING COUNT(DISTINCT dskey) = (SELECT COUNT(*) FROM vals);

This is fully parameterizable and handles NULL values.

EDIT:

Actually, you can do this with your version as well:

SELECT dword FROM Details WHERE dskey = @value1 or @value1 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value2 or @value2 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value3 or @value3 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value4 or @value4 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value5 or @value5 IS NULL;

Intersecting all the rows is an intersection no-op.




回答2:


Gordon this worked like a charm!

use wofwords;
go

DECLARE @value1 varchar(25) = '51a';
DECLARE @value2 varchar(25) = '52b';
DECLARE @value3 varchar(25) = NULL;
DECLARE @value4 varchar(25) = NULL;
DECLARE @value5 varchar(25) = NULL;


SELECT dword FROM Details WHERE dskey = @value1 or @value1 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value2 or @value2 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value3 or @value3 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value4 or @value4 IS NULL
INTERSECT
SELECT dword FROM Details WHERE dskey = @value5 or @value5 IS NULL;
go

It gives me the correct answers and best of all, I can now code up the c# part and have a single query instead of nested ifs...

Johnny



来源:https://stackoverflow.com/questions/43811171/multiple-sql-select-where-with-intersect-placeholder-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!