SQL查询根据订单中其他行的状态包含/排除项目行

时间:2014-05-05 23:26:19

标签: sql sql-server

更新NO 2

通过解决方案1和解决方案2的非常重要的输入,我终于有了一个完全符合它需要的sql。感谢两位用户,感谢他们的帮助。我希望我能将这两个解决方案都标记为答案,但考虑到我的查询基础来自@ papo的解决方案,而且与其他解决方案相比它非常短,我将其标记为我的答案。

最终工作sql

SELECT CNumber, Item, Status
FROM WEBS t1
WHERE (     ((t1.Item IN ('SHIPEXP', 'SHIPPING', 'SHIPINT', 'SHIPBOND', 'GIFT WRAP')) 
                AND EXISTS (SELECT * FROM WEBS
                                WHERE CNumber = t1.CNumber
                                      AND ( Status NOT IN (1, 11, 12, 13, 14, 15, 16, 17)
                                          )
                            )
            )
        OR 
                ( Status NOT IN (1, 11, 12, 13, 14, 15, 16, 17)
                )
      )
AND CNumber = 12140836

更新

我有一个最终查询,如下所示:这是我接受的解决方案。这已经过修改,以适应我的表格结构和其他条款。

问题是如前所述在SCENARIO 2上查询失败,即在完成所有项目时不显示结果。场景1成功。

SELECT t.ItemCode
     , t.ItemStatus
  FROM WEBORDER_STATUS t
 WHERE t.CustOrderNumber = 12140799
   AND  ( ( ( t.ItemCode <> 'SHIPEXP' OR t.ItemCode <> 'SHIPPING' OR t.ItemCode <> 'SHIPINT' OR t.ItemCode <> 'SHIPBOND' OR t.ItemCode <> 'GIFT WRAP'
            ) 
                AND ( t.ItemStatus <> 11 AND t.ItemStatus <> 12 AND 
                      t.ItemStatus <> 1 AND t.ItemStatus <> 13 AND 
                      t.ItemStatus <> 14 AND t.ItemStatus <> 15 AND 
                      t.ItemStatus <> 16 AND t.ItemStatus <> 17
                    )
          )
        OR 
          ( (t.ItemCode = 'SHIPEXP' OR t.ItemCode = 'SHIPPING' OR t.ItemCode = 'SHIPINT' OR t.ItemCode = 'SHIPBOND' OR t.ItemCode = 'GIFT WRAP') 
             AND EXISTS
              ( SELECT 1
                   FROM WEBORDER_STATUS s
                WHERE s.CustOrderNumber = t.CustOrderNumber
                   AND (t.ItemCode <> 'SHIPEXP' OR t.ItemCode <> 'SHIPPING' OR t.ItemCode <> 'SHIPINT' OR t.ItemCode <> 'SHIPBOND' OR t.ItemCode <> 'GIFT WRAP') 
                       AND ( t.ItemStatus <> 11 OR t.ItemStatus <> 12 OR 
                             t.ItemStatus <> 1 OR t.ItemStatus <> 13 OR 
                             t.ItemStatus <> 14 OR t.ItemStatus <> 15 OR 
                             t.ItemStatus <> 16 OR t.ItemStatus <> 17
                           )
              )
          )
       )

在sql server上使用标准Tsql编写SQL查询时需要帮助。

我有一种情况需要根据状态从表中选择项目。

订单编号111的行如下:商品代码发货将始终为已完成。

情景1:

  

ItemCode ----状态

     

123 ----------- Inprogress

     

456 ----------- Inprogress

     

789 -----------已完成

     

SHIPPING ----已完成

预期结果(排除已完成的商品,但包含送货项目,因为所有订单都有运费)

  

123 ----------- Inprogress

     

456 ----------- Inprogress

     

SHIPPING ----已完成


情景2:

  

ItemCode ----状态

     

123 -----------已完成

     

456 -----------已完成

     

789 -----------已完成

     

SHIPPING ----已完成

预期结果(排除已完成的项目,但所有项目均已完成排除SHIPPING)

  

没有结果(所有项目都已完成)

感谢任何帮助或指示。感谢

3 个答案:

答案 0 :(得分:3)

当此订单有未完成的商品时,仅显示SHIPPING行。仅在未完成时显示其他项目。

SELECT OrderNo, ItemCode, Status
FROM table1 t1
WHERE ((ItemCode = 'SHIPPING'
    AND EXISTS (SELECT * FROM table1
         WHERE OrderNo = t1.OrderNo
         AND Status != 'Completed'))
OR Status != 'Completed')
AND OrderNo = 111;

答案 1 :(得分:1)

一种选择是使用EXISTS谓词来测试是否有任何行(除了&#39; SHIPPING&#39;)不是状态&#39;已完成&#39;有条件地退回&#39; SHIPPING&#39;行。

例如:

SELECT t.ItemCode
     , t.Status
  FROM mytable t
 WHERE t.OrderNumber = 111 
   AND (  ( t.ItemCode <> 'SHIPPING' AND t.Status <> 'Completed' 
          )
       OR ( t.ItemCode = 'SHIPPING' AND EXISTS
              ( SELECT 1
                  FROM mytable s
                 WHERE s.OrderNumber = t.OrderNumber
                   AND s.ItemCode <> 'SHIPPING'
                   AND s.Status <> 'Completed'
              )
           )
       )

注意

谓词t.OrderNumber = 111并非必要。这可以省略,或者是其他任何标准。 (我假设您的查询将其作为谓词,因为您显示的示例省略了OrderNumber列。如果省略该谓词,您可能想要在选择列表中返回OrderNumber。)

此:

          ( t.ItemCode <> 'SHIPPING' AND t.Status <> 'Completed' 
          )

获取状态不是已完成的所有未运输的行。 (这可能与第二种情况中的任何行都不匹配。)

此:

          ( t.ItemCode = 'SHIPPING' AND EXISTS
              ( SELECT 1
                  FROM mytable s
                 WHERE s.OrderNumber = t.OrderNumber
                   AND s.ItemCode <> 'SHIPPING'
                   AND s.Status <> 'Completed'
              )
          )
只有当表格中有另一行时,

才会获得SHIPPING行,对于相同的OrderNumber以及“未完成”的状态&#39;。如果子查询返回的行没有,则EXISTS谓词返回FALSE,因此整个表达式的计算结果为FALSE,因此不会返回SHIPPING行。

添加ORDER BY子句以获取按特定顺序返回的行。最后获得SHIPPING行,例如

 ORDER BY CASE t.ItemCode WHEN 'SHIPPING' THEN 2 ELSE 1 END, t.ItemCode

<强>后续

根据您更新的查询,请注意&#34;否定&#34;这个:

    (a = 'b' OR a = 'c')

将是:

    (a <> 'b' AND a <> 'c')

请注意,OR需要替换为AND。例如,如果您通过测试用例,请考虑使用itemCode = 'SHIPEXP'的行。我们知道如果这是真的,那么itemCode <> 'SHIPPING'也将成立。

同样,表达式:

( ItemStatus <> 11 OR ItemStatus <> 12 )

对于ItemStatus的任何非空值,将返回TRUE。 (如果值为11,那么ItemStatus <> 12将为TRUE。这将导致(FALSE OR TRUE),这将返回TRUE。12的值也是如此...(TRUE OR FALSE)将返回TRUE。我认为你想要的是返回一个FALSE。为了得到它,谓词需要一起“和”。

我相信这是您在查询中看到的行为的关键所在。当你期望它们返回FALSE时,你的谓词返回TRUE。


ItemCode上表达谓词的等效(并且更简洁)方式(以查看值是否与值列表中的一个匹配)将是:

t.ItemCode IN ('SHIPEXP','SHIPPING','SHIPINT','SHIPBOND','GIFT WRAP')

同样,ItemStatus的检查可表示为:

t.ItemStatus NOT IN (11,12,1,13,14,15,16,17)

请注意,使用NOT IN时,不等式测试会被“和”在一起而不是“或”。这相当于:

t.ItemStatus <> 11 AND t.itemStatus <> 12 AND ... 

答案 2 :(得分:0)

这是您的第一个场景:

SELECT ItemCode, Status FROM Your_Table WHERE Status!= 'Completed' AND ItemCode !='SHIPPING' 

对于您的第二个场景,可能需要存储过程或嵌套查询的案例