【问题标题】:SELECT DISTINCT with LEFT JOIN, ORDERed BY in t-SQLSELECT DISTINCT with LEFT JOIN, ORDERed BY in t-SQL
【发布时间】:2012-07-20 04:15:15
【问题描述】:

我在 SQL Server 2008 中有下表:

CREATE TABLE tbl (ID INT, dtIn DATETIME2, dtOut DATETIME2, Type INT)

INSERT tbl VALUES
(1, '05:00', '6:00', 1),
(2, '05:00', '7:00', 1),
(3, '05:01', '8:00', 1),
(4, '05:00', '8:00', 1),
(5, '05:00', '6:00', 2),
(6, '05:00', '7:00', 2)

选择相同类型的所有记录的ID,具有相同的dtIn日期,按stOut升序排列:

SELECT DISTINCT tbl.id FROM tbl   
  LEFT JOIN tbl AS t1
  ON tbl.type = t1.type AND
     tbl.dtIn = t1.dtIn
  ORDER BY tbl.dtOut ASC

但它给了我一个错误:

如果 SELECT DISTINCT 是 ORDER BY 项目必须出现在选择列表中 指定

我尝试将 ORDER BY 放在不同的地方,但似乎都不起作用。我在这里做错了什么?

【问题讨论】:

  • 正如错误消息中明确指出的:如果您使用的是SELECT DISTINCT,那么ORDER BY 子句中指定的列也必须出现在所选列的列表中——所以请使用SELECT DISTINCT tbl.id, tbl.dtOut FROM .....跨度>
  • 哦。我知道了。所以我也必须选择它们。嗯...有趣的要求...但是,哦,好吧...

标签: sql sql-server tsql sql-order-by distinct


【解决方案1】:

当您使用“DISTINCT”关键字时,您只能使用 ORDER BY 子句中属于您的选择语句的那些列。所以你只能通过 tbl.id 订购

如果 id 是唯一的,则 DISTINCT 关键字没有任何意义,并且会导致性能下降,您可以将其删除。如果它们不是并且您决定在保持 DISTINCT 的同时选择 tbl.dtOut,则 tbl.id 和 tbl.dtOut 对可以为您提供具有相同 tbl.id 的多个条目,这可能是不希望的。

检查this article 了解可能的解决方法和解释为何禁止此类查询。

【讨论】:

    【解决方案2】:

    您必须在选择列表中包含 tbl.dtOut 列,以便它知道要订购什么。

    SELECT DISTINCT tbl.id, tbl.dtOut FROM tbl   
      LEFT JOIN tbl AS t1
      ON tbl.type = t1.type AND
         tbl.dtIn = t1.dtIn
      ORDER BY tbl.dtOut ASC
    

    【讨论】:

      【解决方案3】:

      按未包含在 DISTINCT 项目列表中的列进行 ORDER 是没有意义的。

      让我们使用一个简单的场景。先来一张表FruitPerson

      Fruit  PersonName
      -----  ------
      Apple  Joe
      Apple  Mary
      Peach  Karen
      Peach  Lance
      

      这是与您尝试执行的操作等效的查询:

      SELECT DISTINCT Fruit
      FROM FruitPerson
      ORDER BY PersonName;
      

      没有ORDER BY 的查询结果如下:

      Fruit
      -----
      Apple
      Peach
      

      但是现在,问题是:引擎应该如何按PersonName 对“Apple”和“Peach”这两个值进行排序? 哪些 PersonNames?每个水果有两个人!究竟应该使用哪个名称来决定是 Apple 还是 Peach 在前?

      相反,将您的查询重写为聚合:

      SELECT Fruit, MinName = Min(PersonName) -- which name to order on
      FROM FruitPerson
      GROUP BY Fruit -- here's how you get your distinctness
      ORDER BY MinName;
      

      【讨论】:

      • 感谢您的解释。你说的方式确实很有意义......我应该承认,SQL 不是我的选择 :) 我现在遇到了另一个问题:(
      【解决方案4】:

      当您将其缩小到单个 id 时,您会创造出每个 id 可能有多个 dtOut 与之关联的可能性。发生这种情况时,Sql Server 将如何知道使用哪个顺序?

      你可以试试:

      SELECT t1.id
      FROM tbl t1
      LEFT JOIN  tbl t2 on t1.type = t2.type AND t1.dtIn = t2.dtIn
      GROUP BY t1.id, t2.dtOut
      ORDER BY t2.dtOut
      

      但是,正如我上面提到的,如果它与右侧表格上的多个记录匹配,则可能会多次列出相同的 id。

      【讨论】:

      • 它似乎不起作用。您的语句产生:不明确的列名“dtOut”。
      • 已修复。忘记 order by 子句中的表别名。
      • 另外:这里的问题是,你真正要求的东西没有任何意义。你说的是“按类型(苹果、橙子等)对这篮水果进行分组,将其缩小到每种类型中的一个,然后按每个水果的采摘时间排序。”在数据库的上下文中,如果篮子里有很多苹果都是在不同时间采摘的,那么它真的不知道该使用什么值。
      • 您可能正在做某事。我完全陷入了我想要实现的目标。抱歉,我不确定这样做的正确方法是什么...我将其发布在单独的线程中:stackoverflow.com/questions/11587533/…
      【解决方案5】:

      您遇到此错误是因为您没有将 (tbl.dtOut) 放入选择列表中。

      SELECT DISTINCT tbl.dtOut FROM tbl    
        LEFT JOIN tbl AS t1  
        ON tbl.type = t1.type AND  
           tbl.dtIn = t1.dtIn  
        ORDER BY tbl.dtOut ASC
      

      将为您提供一个结果集(有 3 行) 如果你也想要 id 字段,那么

      SELECT DISTINCT tbl.dtOut, tbl.ID FROM tbl      
        LEFT JOIN tbl AS t1  
        ON tbl.type = t1.type AND  
           tbl.dtIn = t1.dtIn  
        ORDER BY tbl.dtOut ASC  
      

      (有 6 行,因为它给出了 id/date 字段的不同组合)

      【讨论】:

        猜你喜欢
        • 2013-03-01
        • 2020-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-13
        • 1970-01-01
        • 2021-12-21
        相关资源
        最近更新 更多