【问题标题】:SQL Query to Filter a Table using another Table使用另一个表过滤表的 SQL 查询
【发布时间】:2013-09-22 14:37:08
【问题描述】:

我目前有 2 个如下所示的 SQL 表:

还有……

我需要编写一个 SELECT 语句,从 DataTable 中检索包含与 FilterTable 匹配的行的所有产品。

因此,根据我上面的示例表,如果我要运行查询,它将返回以下结果:

我最近发现了一个类似尝试的问题: SQL query where ALL records in a join match a condition? 但未能成功实现类似的东西

注意 - 我使用的是 Microsoft SQL Server 2008

【问题讨论】:

    标签: sql sql-server-2008 tsql select filter


    【解决方案1】:

    这有点复杂,但这里有一个解决方案。基本上,您需要检查数据表中有多少记录与过滤表中的所有记录匹配。这使用子查询来做到这一点:

    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)
    )  
    

    【讨论】:

    • 这是一个很好的解决方案,但是我想知道是否有办法在不使用计数器的情况下做到这一点?
    • 我很好奇。 “HAVING COUNT() = (SELECT COUNT() FROM FilterTable)”怎么可能指定并选择值 1 和 4? Count 用于计算表中的行数。
    【解决方案2】:

    这将起作用:

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

    如果您想尝试其他事情,我设置了一个 SQL Fiddle: http://sqlfiddle.com/#!3/38b87/6

    编辑:

    更好的答案:

    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
    )
    

    现在,这适用于至少有一个匹配的过滤器,而没有一个不匹配的过滤器。

    【讨论】:

    • 这不应该是 Data.Value = Filter.Value 吗? (因为您使用的是 NOT IN)
    • 但是,这将返回 ID 没有匹配过滤器的字段的 ID。 (因此,如果您有一个新字段,例如“Active2”并对其进行过滤,则将返回上面显示的所有 ID。这是因为我们专门寻找过滤器不匹配的实例。)
    • 不错的尝试,但这并不总是有效 - 以这个为例:sqlfiddle.com/#!3/71703/1 - 话虽如此,我想知道你是否不喜欢更简单的东西......跨度>
    • @user2697139 不。这会查找过滤器匹配的所有 ID,然后将其过滤掉。当然,它会返回 OP 正在寻找的结果。不幸的是,它还会返回任何没有针对该 ID 的过滤器存在的地方。不确定这是否是 OP 想要的。
    • @Hotchips -- 是的,我已经玩了几分钟了。不知道如何使用COUNT。无论哪种方式,+1 努力:D
    【解决方案3】:

    如果您可以使用 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
    

    【讨论】:

      【解决方案4】:

      这是一个使用几个 PIVOT 的选项

      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 
      

      通过对 DATA 表和 FILTER 表执行 PIVOT,它允许将它们排列成内部连接。这将返回两者中匹配的记录,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-14
        • 2022-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多