SQL:不在,同一子查询的不同字段

SQL:不在,同一子查询的不同字段,sql,sql-server,Sql,Sql Server,我有一个子查询,我需要检查两个不同的列,即IT.Item_strItemId和IP.ItemItem_strItemId不应出现在子查询的结果中: SELECT IT.Item_strItemId, IT.Item_strItemDescription FROM tblItem IT LEFT OUTER JOIN VISTAHO.dbo.tblItemPackage IP ON IT.Item_strItemId = IP.Item_strSubItemId W

我有一个子查询,我需要检查两个不同的列,即IT.Item_strItemId和IP.ItemItem_strItemId不应出现在子查询的结果中:

SELECT IT.Item_strItemId,
    IT.Item_strItemDescription
FROM tblItem IT
    LEFT OUTER JOIN VISTAHO.dbo.tblItemPackage IP
        ON IT.Item_strItemId = IP.Item_strSubItemId
WHERE IT.Item_strItemId NOT IN (
        SELECT TI.Item_strItemId
        FROM VISTAHO.dbo.tblTrans_Inventory_HO TI
        GROUP BY TI.Item_strItemId
        HAVING DATEDIFF( MM , MAX(TI.TransI_dtmDateTime) , GetDate() ) <= 6
    ) AND IP.Item_strItemId NOT IN (
        SELECT TI.Item_strItemId
        FROM VISTAHO.dbo.tblTrans_Inventory_HO TI
        GROUP BY TI.Item_strItemId
        HAVING DATEDIFF( MM , MAX(TI.TransI_dtmDateTime) , GetDate() ) <= 6
    )

有没有一种方法可以在不调用两次子查询和不创建表的情况下执行此操作?

这可能正是您真正想要的,但我正在仔细阅读以下几行内容:

SELECT IT.Item_strItemId,
       IT.Item_strItemDescription
FROM dbo.tblItem IT
     INNER JOIN VISTAHO.dbo.tblItemPackage IP ON IT.Item_strItemId = IP.Item_strSubItemId --Assumed INNER JOIN is wanted, as it it an INNER JOIN in the OP
WHERE NOT EXISTS(SELECT 1
                 FROM VISTAHO.dbo.tblTrans_Inventory_HO TI
                 WHERE TI.Item_strItemId IN (IT.Item_strItemId,IP.Item_strItemId)
                 GROUP BY TI.Item_strItemId
                 HAVING DATEDIFF( MM , MAX(TI.TransI_dtmDateTime) , GetDate() ) <= 6);

就性能而言,如果不使用,您将无能为力。即使使用CTE,SQL Server也会重复计算子查询两次

相反,使用不存在,在过去六个日历月内未检查tblTrans_Inventory_HO中的任何内容:


日期表达式看起来更复杂,但复杂的部分都可以在执行之前预先计算。这允许优化器更好地利用上述索引。

反连接是一种常见模式:

SELECT it.item_stritemid
     , it.item_stritemdescription
  FROM tblItem it
  LEFT
  JOIN VISTAHO.dbo.tblItemPackage ip
    ON it.item_stritemid = ip.item_strsubitemid

  LEFT
  JOIN ( SELECT ti.item_stritemid
           FROM VISTAHO.dbo.tblTrans_Inventory_HO ti
          WHERE ti.item_stritemid IS NOT NULL
          GROUP BY ti.item_stritemid
         HAVING DATEDIFF( MM , MAX(ti.transi_dtmdatetime) , GetDate() ) <= 6
       ) t
    ON t.item_stritemid = it.item_stritemid
    OR t.item_stritemid = ip.item_stritemid
 WHERE t.item_stritemid IS NULL
子查询用作内联视图;它是外部联接操作的行源。我们将返回子查询中的所有行以及匹配行。诀窍是WHERE子句中的条件,要求表达式中的NULL值,如果找到匹配行,我们知道该表达式将不会为NULL;我们将删除所有匹配的行,因此只返回不匹配的行

注意:此查询的返回值与原始查询的返回值并不完全相等

原始查询是有效的内部连接到ip。对于外部联接,如果ip中没有匹配的行,ip.item_stritemid的值将为NULL,并且永远不会满足NOT-in条件。为了使这个答案中的查询等价,我们需要删除LEFT关键字


另一个角落的案件。。。我们无法保证ti.item_stritemid始终为非NULL。在原始查询中,当子查询返回NULL值条件时,NOT In子查询的行为将不会计算为TRUE,这与此答案中的查询行为不同。

您是否尝试过CTY您的左连接在此处被隐式转换为内部连接。NULL不能不在任何内容中。这是故意的吗?很好的暗示,我会看看的。谢谢。练习的目的是什么?与保持两列的独立性相比,将两列上的谓词组合到子查询中是否会提高性能,这一点并不确定。如果您只关心DRY,那么可以将定义放入CTE中并引用两次。如果希望确保只对其进行一次评估,则需要对执行计划进行一些检查,以确定是否存在潜在的重写。e、 g.如果它最终位于嵌套循环的内部,那么即使只在查询文本中出现一次,它仍将至少部分执行多次
WHERE NOT EXISTS (SELECT TI.Item_strItemId
                  FROM VISTAHO.dbo.tblTrans_Inventory_HO TI
                  WHERE TI.Item_strItemId = IT.Item_strItemId AND
                        TI.TransI_dtmDateTime >= DATEFROMPARTS(YEAR(DATEADD(month, -6, GETDATE())), MONTH(DATEADD(month, -6, GETDATE())), 1)
                 )
SELECT it.item_stritemid
     , it.item_stritemdescription
  FROM tblItem it
  LEFT
  JOIN VISTAHO.dbo.tblItemPackage ip
    ON it.item_stritemid = ip.item_strsubitemid

  LEFT
  JOIN ( SELECT ti.item_stritemid
           FROM VISTAHO.dbo.tblTrans_Inventory_HO ti
          WHERE ti.item_stritemid IS NOT NULL
          GROUP BY ti.item_stritemid
         HAVING DATEDIFF( MM , MAX(ti.transi_dtmdatetime) , GetDate() ) <= 6
       ) t
    ON t.item_stritemid = it.item_stritemid
    OR t.item_stritemid = ip.item_stritemid
 WHERE t.item_stritemid IS NULL