【问题标题】:How to get the highest value in a row together with all columns' name for equal values如何获得一行中的最大值以及所有列的名称以获得相等的值
【发布时间】:2018-08-02 21:18:10
【问题描述】:

我需要获取一行中的最大值以及列名。问题是在一个分区中可能有几个相等的值。所以我想要的结果是在一列中获得最高值,并且在这种情况下,所有列的名称都用逗号分隔。

这个问题与我之前的问题密切相关:

How to get the highest value in a row together with the column name

让我们使用我之前问题中的 Shnugo 的示例。

DECLARE @tbl TABLE(ID INT IDENTITY,d1 DATE, d2 DATE, d3 DATE);
INSERT INTO @tbl VALUES
('20180101','20180102','20180103')  --one max value
,('20170101','20190102','20190102'); --two max values

对于 ID=2,有两个最大值,所以我想要完成的是一个具有 ID 列、max_date 列和第三列列名称的表。因此,对于 ID=2,我想获得两列的名称 (d2,d3)。

【问题讨论】:

  • 编辑问题添加一些示例数据和所需的结果会有所帮助。
  • 你试过 MAX(column_name) 了吗?结果与您想要的结果有何不同?

标签: sql sql-server tsql


【解决方案1】:

试试这样:

DECLARE @tbl TABLE(ID INT IDENTITY,d1 DATE, d2 DATE, d3 DATE);
INSERT INTO @tbl VALUES
 ('20180101','20180102','20180103')  --one max value
,('20170101','20190102','20190102'); --two max values

WITH cte AS
(
    SELECT TOP 1 WITH TIES
           t.ID 
          ,y.value('text()[1]','date') d
          ,y.value('local-name(.)','varchar(100)') c
    FROM @tbl t
    CROSS APPLY(SELECT d1,d2,d3 FOR XML PATH('d'),TYPE) A(x)
    CROSS APPLY x.nodes('/d/*') B(y) 
    ORDER BY DENSE_RANK() OVER(PARTITION BY ID ORDER BY y.value('text()[1]','date') DESC)
)
SELECT cte1.ID
      ,cte1.d 
      ,STUFF((SELECT ',' + cte2.c 
        FROM cte cte2 
        WHERE cte1.ID=cte2.ID
        FOR XML PATH('')),1,1,'') cs
FROM cte cte1
GROUP BY ID,d;

对于 SQL-Server 2017+,您最好使用STRING_AGG()。

我已经添加了一些解释at the previous answer

【讨论】:

  • 谢谢,它可以工作,但问题是执行时间超过 20 分钟(仍在运行),尽管我在所有临时表上创建了聚集索引。理想情况下,如果一个 ID 有多个最大日期,我希望拥有所有列的名称,但在我看来这可能太耗时了。
  • @Arkadiusz 如果有这么多行,这似乎是错误的设计......您的日期列应该存在于相关的“状态”表中......另一个选项是插入触发器和更新或持久计算列,它将附加列设置为您需要的值。每当这些日期之一发生变化时,您都可以维护一个边表,您可以在其中添加一行。您不应即时为数百万行计算此信息。顺便说一句:DBA 讨厌在 db 服务器上使用 CPU 消耗方法...
【解决方案2】:

您可以尝试类似的代码来获取信息并插入表中。您必须根据需要更新下面的CASE 逻辑以添加其他条件。

DECLARE @tbl TABLE(ID INT IDENTITY,d1 DATE, d2 DATE, d3 DATE);
INSERT INTO @tbl VALUES
('20180301','20180102','20180103')  --one max value
,('20170101','20190102','20190102'); --two max values

SELECT ID, LEFT(MAXDateInfo,10) AS maxdate, RIGHT(maxdateInfo,2) as ColumnName
FROM
(SELECT ID,CASE WHEN d1 > d2 AND d1 > d3 THEN CONCAT(d1,'-','d1')
               WHEN d2 > d1 AND d2 > d3 THEN CONCAT(d2,'-','d2')
               WHEN d3 > d1 AND d3 > d3 THEN CONCAT(d3,'-','d3')
           END AS MAXDateInfo
FROM @tbl) as t

【讨论】:

    猜你喜欢
    • 2019-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    相关资源
    最近更新 更多