【问题标题】:Excluding query result with in and not in用 in 和 not in 排除查询结果
【发布时间】:2017-11-15 01:21:42
【问题描述】:

我有两张桌子:

  • 人员(BusinessEntityID、FirstName、LastName)
  • 销售(OrderID、CustomerID、OrderDate)

我想列出在 2011 年和 2014 年都下过订单但在 2012 年和 2013 年从未下过订单的人

我希望这个查询能够正常工作,但它仍在列出 2013 年的订单

SELECT 
    s.CustomerID,p.LastName,p.FirstName, s.OrderDate
FROM 
    Sales.SalesOrderHeader s,Person.Person p
WHERE 
    s.CustomerID = p.BusinessEntityID 
    AND s.CustomerID IN (SELECT CustomerID 
                         FROM Sales.SalesOrderHeader
                         WHERE YEAR(OrderDate) IN (2011, 2014)
                         GROUP BY CustomerID
                         HAVING COUNT(CustomerID) > 1)
    AND s.CustomerID NOT IN (SELECT CustomerID 
                             FROM Sales.SalesOrderHeader
                             WHERE YEAR(OrderDate) IN (2012, 2013)
                             GROUP BY CustomerID
                             HAVING COUNT(CustomerID) > 1)
GROUP BY 
    s.CustomerID, p.LastName, p.FirstName, s.OrderDate

结果:

CustomerID     LastName    FirstName    OrderDate
---------------------------------------------------------------
11001          Young       Amber        2011-06-17 00:00:00.000
11001          Young       Amber        2013-06-18 00:00:00.000
11001          Young       Amber        2014-05-12 00:00:00.000
11017          Clark       Chloe        2011-06-14 00:00:00.000
11017          Clark       Chloe        2013-06-03 00:00:00.000
11017          Clark       Chloe        2014-03-16 00:00:00.000
11018          Mehta       Joe          2011-06-19 00:00:00.000
11018          Mehta       Joe          2013-06-18 00:00:00.000
11018          Mehta       Joe          2014-03-26 00:00:00.000

【问题讨论】:

  • 将表格和数据发布为文本READ THIS 以了解原因
  • 你的 rdbms 是什么? Sql Server、postgres、oracle?
  • 你可以使用senseful.github.io/text-table来格式化你的表格
  • 您说“我想列出人员”,但您的查询列出了汇总订单。 在开始编写代码之前了解(并正确陈述)您的目标。
  • Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSI JOIN 语法-92 SQL 标准(25 年前),不鼓励使用它

标签: sql sql-server


【解决方案1】:

having COUNT(CustomerID)>1 表示您有超过 1 个订单 (2,3,4...)。

在第一个子查询中,使用having COUNT(CustomerID)>0

在第二个中,使用:

s.CustomerID
not in(select CustomerID from Sales.SalesOrderHeader where YEAR(OrderDate) 
in(2012,2013))

没有分组和有

【讨论】:

    【解决方案2】:

    使用条件COUNT()

      SELECT BussinessEntityID, FirstName, LastName
      FROM Person P
      JOIN Sales S
        ON P.BussinessEntityID = S.CustomerID
      GROUP BY BussinessEntityID, FirstName, LastName
      HAVING COUNT(DISTINCT CASE WHEN YEAR(OrderDate) IN (2011,2014)
                                 THEN YEAR(OrderDate)
                            END)  = 2
         AND COUNT(DISTINCT CASE WHEN YEAR(OrderDate) IN (2012,2013)
                                 THEN YEAR(OrderDate)
                            END) = 0
    

    【讨论】:

      【解决方案3】:

      如果您使用的是 SQL Server,我认为您可以使用 EXCEPT 关键字获得您想要的结果,如下面的查询所示。我现在无法测试它,所以我可能错了......

      SELECT s.CustomerID,p.LastName,p.FirstName, s.OrderDate
      FROM Sales.SalesOrderHeader s,Person.Person p
      WHERE s.CustomerID = p.BusinessEntityID 
      AND Year(s.OrderDate) IN (2011, 2014)
      
      EXCEPT
      
      SELECT s.CustomerID,p.LastName,p.FirstName, s.OrderDate
      FROM Sales.SalesOrderHeader s,Person.Person p
      WHERE s.CustomerID = p.BusinessEntityID 
      AND Year(s.OrderDate) IN (2012, 2013)
      

      【讨论】:

        【解决方案4】:

        你可以这样做。

        create table #Person(BussinessEntityID int ,FirstName varchar(100), LastName varchar(100));
        create table #Sales(OrderID int ,CustomerID int ,OrderDate datetime);
        
        SELECT s.CustomerID,p.LastName,p.FirstName, s.OrderDate
        FROM #Sales s,#Person p
        WHERE s.CustomerID = p.BussinessEntityID 
        and exists (select top 1 1 from #Sales X Where x.CustomerID=p.BussinessEntityID and Year(x.OrderDate)=2011)
        and exists (select top 1 1 from #Sales X Where x.CustomerID=p.BussinessEntityID and Year(x.OrderDate)=2014)
        and not exists (select top 1 1 from #Sales X Where x.CustomerID=p.BussinessEntityID and Year(x.OrderDate) in (2012,2013));
        

        【讨论】:

          【解决方案5】:

          您可以使用 IN 和 NOT EXISTS 的组合。

          如果我使用您的示例输出,例如:

          --Your sample output
          DECLARE @Person TABLE (BusinessEntityID int, FirstName varchar(100), LastName varchar(100))
          DECLARE @Sales TABLE (OrderID int IDENTITY(1,1),CustomerID int, OrderDate date)
          
          INSERT INTO @Person VALUES (11001, 'Amber', 'Young'),(11017, 'Chloe', 'Clark')
                                    ,(11018, 'Joe', 'Mehta')
          
          INSERT INTO @Sales (CustomerID, OrderDate)
          VALUES (11001, '2014-03-26'),(11001, '2013-06-18'),(11001, '2011-06-18')
                ,(11017, '2014-03-16'),(11017, '2013-06-03'),(11017, '2011-06-14')
                ,(11001, '2014-05-12'),(11001, '2013-06-18'),(11001, '2011-06-17')
          
          
          SELECT DISTINCT S.CustomerID, P.LastName, P.FirstName
            FROM @Sales S INNER JOIN @Person P ON S.CustomerID = P.BusinessEntityID
           WHERE YEAR(S.OrderDate) IN (2011, 2014)
             AND NOT EXISTS (SELECT *
                               FROM @Sales S2
                              WHERE S2.CustomerID = S.CustomerID
                                AND YEAR(S.OrderDate) IN (2012, 2013)
                            )
          

          产生输出:

          CustomerID  LastName    FirstName   OrderDate
          11001       Young       Amber       2011-06-17
          11001       Young       Amber       2011-06-18
          11001       Young       Amber       2014-03-26
          11001       Young       Amber       2014-05-12
          11017       Clark       Chloe       2011-06-14
          11017       Clark       Chloe       2014-03-16
          

          【讨论】:

            猜你喜欢
            • 2019-05-12
            • 1970-01-01
            • 1970-01-01
            • 2017-02-06
            • 2012-01-17
            • 2013-05-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多