【问题标题】:How to get columns from multiple rows in a single row in SQL如何在SQL中从单行中的多行获取列
【发布时间】:2021-01-22 04:47:41
【问题描述】:

我想获得 2 列 col_a 和 col_b 的值,分别表示其他列的最小值和最大值。例如:

id last_updated col_a col_b
1 2021-01-01 abc xyz
1 2021-01-02 abc_0 xyz_0
1 2021-01-03 abc_1 xyz_1
1 2021-01-04 abc_2 xyz_2
2 2021-01-01 abc xyz
2 2021-01-01 abc xyz
...

我想得到结果:

|1|abc|abc_2|xyz|xyz_2|

这是按 id 分组的结果,并获取这些列的值,同时将 min 和 max 的条件放在其他列上(last_updated)。

我想出了以下查询:

select id, max(last_updated), min(last_updated)
from my_table
group by id

这给了我 id 和 min 和 max 日期,但不是其他 2 列。我不确定如何获取同一查询中两个日期的其他 2 列的值。

【问题讨论】:

    标签: sql sql-server database tsql


    【解决方案1】:

    您可以使用MINMAX解析函数如下:

    select id,
           max(case when mindt = last_updated then col_a end) as min_col_a,
           max(case when maxdt = last_updated then col_a end) as max_col_a,
           max(case when mindt = last_updated then col_b end) as min_col_b,
           max(case when maxdt = last_updated then col_b end) as max_col_b
      from
    (select t.*,
           min(last_updated) over (partition by id) as mindt,
           max(last_updated) over (partition by id) as maxdt
      from your_table t) t
    group by id
    

    【讨论】:

      【解决方案2】:

      我们可以两次使用ROW_NUMBER 来查找每个id 记录组的第一行和最后一行,按last_updated 的顺序排列。然后,按id 聚合并转出各种col_acol_b 值的列。

      WITH cte AS (
          SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY last_updated) rn_min,
                    ROW_NUMBER() OVER (PARTITION BY id ORDER BY last_updated DESC) rn_max
          FROM yourTable
      )
      
      SELECT
          id,
          MAX(CASE WHEN rn_min = 1 THEN col_a END) AS col_a_min,
          MAX(CASE WHEN rn_max = 1 THEN col_a END) AS col_a_max,
          MAX(CASE WHEN rn_min = 1 THEN col_b END) AS col_b_min,
          MAX(CASE WHEN rn_max = 1 THEN col_b END) AS col_b_max
      FROM cte
      GROUP BY id;
      

      【讨论】:

      • 我怎样才能在不同的列中获得这些?我已经更新了问题
      • 答案已更新。您最初的问题使您看起来想要一个 CSV 字符串。
      【解决方案3】:

      不是最简洁的解决方案,但演示了另一种获取所需数据的方法。我们加入表格本身,因为我们通常需要 2 行的数据,然后我们使用 cross apply 将其限制为第一个和最后一个。

      select T1.id, T2.col_a, T1.col_a, T2.col_b, T1.col_b
      from #my_table T1
      inner join #my_table T2 on T1.id = T2.id
      cross apply (
        select id, max(last_updated) MaxLastUpdated, min(last_updated) MinLastUpdated
        from #my_table
        group by id
      ) X
      where T1.last_updated = X.MaxLastUpdated and T2.last_updated = X.MinLastUpdated;
      

      根据提供的示例数据,这似乎比row_number() 解决方案的性能更差。最快的解决方案是解析函数。

      【讨论】:

        【解决方案4】:
        select id,max(last_updated) last_updatedMax, min(last_updated) last_updatedMin,max(col_aMax) col_aMax, max(col_aMin) col_aMin,max(col_bMax) col_bMax, max(col_bMin) col_bMin
        from
        (
            select 
                *
                , first_value(col_a) OVER (PARTITION BY  id ORDER BY last_updated desc) as  col_aMax
                , first_value(col_a) OVER (PARTITION BY  id ORDER BY last_updated asc) as  col_aMin
                , first_value(col_b) OVER (PARTITION BY  id ORDER BY last_updated desc) as  col_bMax
                , first_value(col_b) OVER (PARTITION BY  id ORDER BY last_updated asc) as  col_bMin
             from my_table
        ) t
        group by id
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-06
          • 1970-01-01
          相关资源
          最近更新 更多