2013-09-18 3 views
1

я в настоящее время есть 2 таблицы SQL, которые выглядят следующим образом:SQL запросов для фильтрации таблицы с использованием другой таблицы

Data Table

и ...

filter table

Мне нужно написать SELECT, который извлекает все продукты из DataTable, которые содержат строки, соответствующие FilterTable.

Так на основе моих например таблицы выше, если бы я, чтобы выполнить запрос, он будет возвращен следующий результат:

Result table

Я недавно нашел вопрос, который вроде попыток этого: SQL query where ALL records in a join match a condition? но не увенчались успехом в реализации нечто подобное

Примечание - Я использую Microsoft SQL Server 2008

ответ

4

Th является немного сложным, но здесь есть одно решение. В основном вам нужно проверить, сколько записей из данных сопоставимо со всеми записями из фильтра. При этом используется подзапрос, чтобы сделать это:

SELECT * 
FROM DataTable 
WHERE ID IN (
    SELECT DT.ID 
    FROM DataTable DT 
    JOIN FilterTable FT ON FT.Name = DT.Name 
      AND FT.Value = DT.VALUE 
    GROUP BY DT.ID 
    HAVING COUNT(*) = (SELECT COUNT(*) FROM FilterTable) 
) 
+0

Это хорошее решение, однако я задаюсь вопросом, есть ли способ сделать это без использования счетчика? – StevenP

+0

Мне любопытно. Как возможно, что «HAVING COUNT (*) = (SELECT COUNT (*) FROM FilterTable)» укажите и выберите значения 1 и 4? Граф используется для подсчета количества строк в таблице. –

1

Это будет работать:

SELECT * FROM Data WHERE ID NOT IN (
    SELECT ID FROM Data JOIN Filter 
     on Data.Name = Filter.Name and Data.Value <> Filter.Value 
) 

Я создал SQL скрипку, если вы хотите попробовать другие вещи: http://sqlfiddle.com/#!3/38b87/6

EDIT:

Лучше ответ:

SELECT * 
FROM DATA 
WHERE ID NOT IN (
    SELECT ID 
    FROM DATA 
    JOIN Filter ON DATA.Name = Filter.Name 
    AND DATA.Value <> Filter.Value 
) AND ID IN 
(
    SELECT ID 
    FROM DATA 
    JOIN Filter ON DATA.Name = Filter.Name 
) 

Теперь это подходит, где есть хотя бы один фильтр, который соответствует, и ни одно из них не делают.

+0

Должно ли это быть Data.Value = Filter.Value? (поскольку вы используете NOT IN) – AlexT82

+1

Это, однако, возвращает идентификаторы, в которых идентификатор не имеет поля, соответствующего фильтру.(Так что, если у вас есть новое поле, скажем «Active2», и отфильтруйте его, все идентификаторы, показанные выше, будут возвращены. Это потому, что мы специально ищем экземпляры, где фильтр не соответствует.) – Hotchips

+2

Приятная попытка , но это не всегда будет работать - возьмите это, например: http://sqlfiddle.com/#!3/71703/1 - с этим сказанным, интересно, если вы не на что-то более простое ... – sgeddes

0

Если вы используете sp_executesql (вы используете процедуру).

SET NOCOUNT ON 
GO 

    CREATE TABLE Data 
    (
     [ID] INT 
     ,[Name] VARCHAR(12) 
     ,[Value] VARCHAR(2) 
    ) 

    CREATE TABLE Filter 
    (
     [Name] VARCHAR(12) 
     ,[Value] VARCHAR(2) 
    ) 

    INSERT INTO Data ([ID], [Name], [Value]) 
    VALUES (1, 'productname', 'A') 
      ,(1, 'cost', '20') 
      ,(1, 'active', 'Y') 
      ,(2, 'productname', 'A') 
      ,(2, 'cost', '20') 
      ,(2, 'active', 'N') 
      ,(3, 'productname', 'B') 
      ,(3, 'cost', '20') 
      ,(3, 'active', 'Y') 
      ,(4, 'productname', 'A') 
      ,(4, 'cost', '20') 
      ,(4, 'active', 'Y') 

    INSERT INTO Filter ([Name], [Value]) 
    VALUES ('productname', 'A') 
      ,('active', 'Y') 

    DECLARE @SQLColumns NVARCHAR(MAX) = SUBSTRING((SELECT DISTINCT ',[' +[Name] +']' FROM Data FOR XML PATH('')),2,4000) 
    DECLARE @SQLFilterColumns NVARCHAR(MAX) = SUBSTRING((SELECT 'AND [' +[Name] +'] = ''' + [Value] + ''' ' FROM Filter FOR XML PATH('')),4,4000) 

    DECLARE @SQLStatement NVARCHAR(MAX) = N' 
    ;WITH DataSource ([ID]) AS 
    (
     SELECT [ID] 
     FROM 
     (
      SELECT [ID] 
        ,[Name] 
        ,[Value] 
      FROM Data 
     ) DataSource 
     PIVOT 
     (
      MAX([Value]) FOR [Name] IN (' + @SQLColumns+ ') 
     ) PVT 
     WHERE ' + @SQLFilterColumns + ' 
    ) 
    SELECT DT.[ID] 
      ,DT.[Name] 
      ,DT.[Value] 
    FROM Data DT 
    INNER JOIN DataSource DS 
     ON DT.[ID] = DS.[ID] 
    ' 

    EXECUTE sp_executesql @SQLStatement 

    DROP TABLE Data 
    DROP TABLE Filter 

SET NOCOUNT OFF 
GO 
0

Вот вариант с помощью пары цапф

DECLARE @Data table ([ID] INT, [Name] VARCHAR(12), [Value] VARCHAR(2)) 

DECLARE @Filter TABLE ([Name] VARCHAR(12), [Value] VARCHAR(2) ) 

    INSERT INTO @Data ([ID], [Name], [Value]) 
    VALUES (1, 'productname', 'A') 
      ,(1, 'cost', '20') 
      ,(1, 'active', 'Y') 
      ,(2, 'productname', 'A') 
      ,(2, 'cost', '20') 
      ,(2, 'active', 'N') 
      ,(3, 'productname', 'B') 
      ,(3, 'cost', '20') 
      ,(3, 'active', 'Y') 
      ,(4, 'productname', 'A') 
      ,(4, 'cost', '20') 
      ,(4, 'active', 'Y') 

    INSERT INTO @Filter ([Name], [Value]) 
    VALUES ('productname', 'A') 
      ,('active', 'Y'); 

SELECT * 
FROM ( SELECT * 
     FROM (select [ID], [Name], [value] from @Data) as s 
     PIVOT 
     (MAX([value]) FOR [name] in ([productname], [active]) 
     ) as pvt) B 
INNER JOIN 
     ( SELECT * 
     FROM (select [name], [value] from @Filter) as f 
     PIVOT 
     (MAX([value]) for [Name] IN ([productname], [active]) 
     ) AS fpvt 
    ) F 
ON F.active = b.active and f.productname = b.productname 

Делая PIVOT на столе DATA, а затем на стол ФИЛЬТР, это позволяет им быть выстроены для внутреннего соединения. Это возвращает записи, соответствующие друг другу,

Смежные вопросы