【问题标题】:Unsure how to order this in SQL Server不确定如何在 SQL Server 中订购
【发布时间】:2017-02-12 21:01:07
【问题描述】:

我正在尝试订购一个结果集,它看起来很简单,但我遇到了一些麻烦。

一个人可以有多种地址类型,NULL、Civic 或 Mailing。 我希望任何地址为 NULL 的人都列在顶部,然后是他们的公民和邮寄地址。

如果您没有null 地址,那么他们的公民和/或邮寄地址会排在拥有null 的任何人之后。

我试过按地址排序只会首先列出所有nulls,按姓名、地址排序会部分起作用,但不能保证nulls 的人会排在第一位。

以这组为例

ID  Person      Address
-------------------------
1   Person A    Civic
1   Person A    Mailing
2   Person B    NULL
2   Person B    Civic
2   Person B    Mailing
3   Person C    NULL
3   Person C    Civic
3   Person C    Mailing

应该是:

ID   Person     Address
-------------------------
2   Person B    NULL
2   Person B    Civic
2   Person B    Mailing
3   Person C    NULL
3   Person C    Civic
3   Person C    Mailing
1   Person A    Civic
1   Person A    Mailing

【问题讨论】:

  • 可能是按名字排序的
  • 名称或 ID。没关系@TheGameiswar
  • @TheGameiswar 在问题ordering by name, address, will work in part 中有说明。下次会说清楚

标签: sql sql-server-2008 select sql-order-by


【解决方案1】:

你也可以试试这个

SELECT *
FROM @tab
ORDER BY Person,
         (CASE
              WHEN Address IS NULL
              THEN 'a'
              ELSE Address
          END);

【讨论】:

  • You can this this one too - 应该是You can use this ordering too?
【解决方案2】:

简单

select *
from mytable
order by min(case when Address is null then 0 else 1 end) over (partition by ID), id, Address;

虽然 Sql Server 在 WHERE 中不接受窗口函数,但在 ORDER BY 中是可以的。所以这里不需要任何子查询。

【讨论】:

  • 奇怪的是您的帖子进入了低质量队列(查看您的代表),甚至更奇怪的是(查看我的代表)我会要求您添加详细信息,因为仅代码答案不是这里很受欢迎。 (但是,这是处理此类情况的accepted way)。
  • 感谢@Al.G.希望我添加的解释对读者有帮助。
  • 是的,它“不再可审查”。顺便说一句,“简单”这个词每次都从我自己的答案中删除。
【解决方案3】:

试试这个 CTE 版本。

;WITH CTE_1
  AS (SELECT Id, Person, Address, 
               SUM(CASE WHEN PERSON IS NULL THEN 1 ELSE 0 END) OVER 
              (PARTITION BY person) AS RNO
         FROM   addresses) 
  SELECT Id, Person, Address
  FROM CTE_1
  ORDER BY RNO DESC, person ASC, address ASC

【讨论】:

    【解决方案4】:

    Tim Biegeleisen 在计算address IS NULL 所在的记录数方面有正确的想法。我认为通过使用带有 windows 子句的sum 而不是使用子查询加入它,可以使查询更优雅(并且可能执行得更好):

    SELECT id, person, address
    FROM   (SELECT id, 
                   person, 
                   address, 
                   SUM(CASE WHEN PERSON IS NULL THEN 1 ELSE 0 END) OVER 
                      (PARTITION BY person) AS s
            FROM   addresses) t
    ORDER BY s DESC, person ASC, address ASC
    

    【讨论】:

      【解决方案5】:

      这个解决方案使用一个子查询来确定每个ID(人)是否有一个NULL值一个他的地址。如果一个人确实有一个NULL 值,那么保存的计数的总和将大于零。那些拥有至少一个NULL 地址的人会在那些没有至少一个NULL 的人之前排在第一位。在此之后,结果集按ID 后跟Address 排序,您可能已经这样做了。

      SELECT t1.*
      FROM yourtable
      INNER JOIN
      (
          SELECT ID,
                 SUM(CASE WHEN Address IS NULL THEN 1 END) AS hasNull
          FROM yourTable
          GROUP BY ID
      ) t2
          ON t1.ID = t2.ID
      ORDER BY CASE WHEN t2.hasNull > 0 THEN 0 ELSE 1 END,
               t1.ID,
               t1.Address
      

      【讨论】:

      • 您是否在生产中使用这么多记录?或者您是否打算离线运行此查询以供参考?
      • 这是一个生产服务器。就字段而言,这是一个联合的大数据集。该查询仅返回 5k 条记录,大约需要 4.5 秒。排序使时间加倍。不过答案很好:)
      • 聚合可能是一个真正的性能杀手,但我没有看到任何明显的改进方法,除了使用不完全涉及它的不同方法。连接也可能是个问题。
      猜你喜欢
      • 2020-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 2015-11-09
      相关资源
      最近更新 更多