【问题标题】:Complex SQL Exclude Logic with set based operations具有基于集合的操作的复杂 SQL 排除逻辑
【发布时间】:2013-10-01 13:41:44
【问题描述】:

我更喜欢使用集合逻辑,而不是使用游标或其他东西遍历表,但如果需要,它可以完成。

我基本上是在存储过程中准备一个视图,它将在其他地方用于 BI。现在,存储过程只是一个从具有相当数量的连接和其他随机逻辑的各种表中提取的选择语句。

以下是有关表格外观的示例。首先,将返回的表,其次是用户想要排除的内容。

我想查看 excludes 表中的每条记录,然后将其作为过滤器应用到第一个表中,这样它将消除项目匹配的所有行。 (它会变得有点复杂,因为他们可以选择消除整个 LocationCode,然后将级联到所有 WarehouseCodes 和它下面的所有东西。它基本上是一个层次结构。但我想把大致的想法记下来)。

我不确定如何使用 NOT EXISTS 来执行此操作,因为我必须逐行进行。我不确定我是否必须使用游标或以另一种方式迭代。我想知道 SQL 中是否还有其他我不知道的工具。

任何关于如何有效地消除基于其他表值的行的建议将不胜感激,谢谢。

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    如果您想从 Table1 中获取除 Table2 中相似的行之外的整行,您可以这样做:

    select * -- Column list here
    from Table1 as t
    where
        not exists (
            select t.LocationCode, t.WarehouseCode, t.WarehouseName, t.StorageAddress
            intersect
            select t2.LocationCode, t2.WarehouseCode, t2.WarehouseName, t2.StorageAddress
            from Table2 as t2
        )
    

    或者更方便

    select * -- Column list here
    from Table1 as t
    where
        not exists (
            select *
            from Table2 as t2
            where
                t2.LocationCode = t.LocationCode and
                t2.WarehouseCode = t.WarehouseCode and
                t2.WarehouseName = t.WarehouseName and
                t2.StorageAddress = t.StorageAddress
        )
    

    【讨论】:

    • 我能够使用第二个查询,然后在 WHERE 子句中有以下语句有条件地限制( AND (t2.WarehouseCode = 'ALL' OR t2.WarehouseCode = t1.WarehouseCode) ) .
    【解决方案2】:

    查看EXCEPT 子句,其工作方式类似于UNION

    select col1, col2, col3 from yourtable
    EXCEPT
    select col1, col2, col3 from exceptions
    

    【讨论】:

    • 我不确定我是否希望它返回不同的值,并且必须匹配查询中的行可能需要一些额外的步骤来设置整体
    【解决方案3】:

    这里有两件事要解决。在第一种情况下,您已经解释了 Exclude 表的列数与实际表中的列数相同。我在这里假设此表中的某些列将是 “可以为空”,有些可能不是。因此,在排除期间,您也需要注意这一点。由于性能原因,我看到“左连接”是一个很好的候选者,而且您只能在需要时对选定的列执行 MATCHING。在您现在的情况下,似乎所有列都需要匹配,但请考虑将来是否在表中添加了 Identity/datetime/timestamp 之类的列。 请参阅下面的代码。如果此表中的数据量很大,则适当的非聚集和/或过滤索引将帮助您提高性能,但如果您发现视图查询很慢,那将是在稍后阶段。

    对于您提到的第二部分,稍后您可能会决定完全排除位置代码并且存在分层依赖关系。 我会说保持这个分开,直到你有确切的要求。

        DECLARE @AllData TABLE
        (
            ID      INT         NOT NULL PRIMARY KEY
            ,FName  sysname     NOT NULL
            ,LName  sysname     NOT NULL
            ,MName  sysname     NULL
        )
    
        DECLARE @ExcludeData TABLE
        (
            ID      INT         NOT NULL PRIMARY KEY
            ,FName  sysname     NOT NULL
            ,LName  sysname     NOT NULL
            ,MName  sysname     NULL
        )
    
        INSERT INTO @AllData( ID, FName, LName, MName )
                    SELECT 1,'Fname1','Lname1','MName1'
        UNION ALL   SELECT 2,'Fname2','Lname2',NULL
        UNION ALL   SELECT 3,'Fname3','Lname3','Mname3'
        UNION ALL   SELECT 4,'Fname4','Lname4',NULL
    
        INSERT INTO @ExcludeData( ID, FName, LName, MName )
                    SELECT 1,'Fname1','Lname1','MName1'
        UNION ALL   SELECT 2,'Fname2','Lname2',NULL
    
        SELECT a.ID,a.FName,a.LName,a.MName
        FROM @AllData a
        LEFT JOIN @ExcludeData b
        ON 
            ((a.ID=b.ID) OR (a.id IS NULL AND b.id IS NULL))
            AND
            ((a.FName=b.FName) OR (a.FName IS NULL AND b.FName IS NULL))
            AND
            ((a.LName=b.LName) OR (a.LName IS NULL AND b.LName IS NULL))
            AND
            ((a.MName=b.MName) OR (a.MName IS NULL AND b.MName IS NULL))
        WHERE 
            (b.ID IS NULL AND b.FName IS NULL AND b.LName IS NULL AND b.MName IS NULL)
    

    【讨论】:

    • 以你给出的例子为例。假设排除表中有一条记录是 [5, 'Fname3', 'Lnname3', 'ALL']。假设“All”意味着他们想要消除所有 Fname3 和 Lname3 组合,而不考虑 Mname。你怎么能解释这一点,同时仍然让其他行按中间名列过滤?
    猜你喜欢
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多