You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将同一Person_id的多行起止日期记录合并为单行多列的技术需求

行转列实现同一Person_id的多日期记录合并

嘿,这个需求我太熟悉了!本质上就是把同一Person_id+Store_id下的多行起止日期记录行转列(Pivot),不同数据库的实现思路大同小异,我给你几个主流数据库的解决方案,你按需取用:

核心思路

先给每组(Person_id+Store_id)的记录按Startdate排序编序号,再通过条件聚合(或数据库自带的Pivot函数)把每个序号对应的Startdate和enddate转成单独的列。


MySQL 解决方案

MySQL没有原生的Pivot函数,用条件聚合最直接:

SELECT 
    Person_id,
    Store_id,
    MAX(CASE WHEN seq = 1 THEN Startdate END) AS Startdate1,
    MAX(CASE WHEN seq = 1 THEN enddate END) AS enddate1,
    MAX(CASE WHEN seq = 2 THEN Startdate END) AS Startdate2,
    MAX(CASE WHEN seq = 2 THEN enddate END) AS enddate2,
    MAX(CASE WHEN seq = 3 THEN Startdate END) AS Startdate3,
    MAX(CASE WHEN seq = 3 THEN enddate END) AS enddate3,
    MAX(CASE WHEN seq = 4 THEN Startdate END) AS Startdate4,
    MAX(CASE WHEN seq = 4 THEN enddate END) AS enddate4
    -- 要是你的记录超过4条,继续加对应的CASE语句就行
FROM (
    SELECT 
        Person_id,
        Store_id,
        Startdate,
        enddate,
        -- 给每组记录按Startdate排序编序号
        ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
    FROM your_table_name
    WHERE Person_id = '10000351067' -- 针对特定Person_id,去掉就处理所有用户
) t
GROUP BY Person_id, Store_id;

SQL Server 解决方案

SQL Server有两种常用方式,条件聚合最通用,也可以用原生的Pivot函数:

方式1:条件聚合(和MySQL逻辑一致)

SELECT 
    Person_id,
    Store_id,
    MAX(CASE WHEN seq = 1 THEN Startdate END) AS Startdate1,
    MAX(CASE WHEN seq = 1 THEN enddate END) AS enddate1,
    MAX(CASE WHEN seq = 2 THEN Startdate END) AS Startdate2,
    MAX(CASE WHEN seq = 2 THEN enddate END) AS enddate2,
    MAX(CASE WHEN seq = 3 THEN Startdate END) AS Startdate3,
    MAX(CASE WHEN seq = 3 THEN enddate END) AS enddate3,
    MAX(CASE WHEN seq = 4 THEN Startdate END) AS Startdate4,
    MAX(CASE WHEN seq = 4 THEN enddate END) AS enddate4
FROM (
    SELECT 
        Person_id,
        Store_id,
        Startdate,
        enddate,
        ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
    FROM your_table_name
    WHERE Person_id = '10000351067'
) t
GROUP BY Person_id, Store_id;

方式2:UNPIVOT + PIVOT 组合

适合需要转多个字段的场景:

WITH numbered AS (
    -- 先给每组记录编号
    SELECT 
        Person_id,
        Store_id,
        Startdate,
        enddate,
        ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
    FROM your_table_name
    WHERE Person_id = '10000351067'
),
unpivoted AS (
    -- 把Startdate和enddate拆成键值对
    SELECT 
        Person_id,
        Store_id,
        CONCAT(col_name, seq) AS new_col,
        col_value
    FROM numbered
    UNPIVOT (
        col_value FOR col_name IN (Startdate, enddate)
    ) up
)
-- 把组合后的列名转成实际列
SELECT 
    Person_id,
    Store_id,
    Startdate1, enddate1, Startdate2, enddate2, Startdate3, enddate3, Startdate4, enddate4
FROM unpivoted
PIVOT (
    MAX(col_value) FOR new_col IN (Startdate1, enddate1, Startdate2, enddate2, Startdate3, enddate3, Startdate4, enddate4)
) p;

PostgreSQL 解决方案

PostgreSQL可以用条件聚合,也可以用专门的crosstab函数:

方式1:条件聚合(通用写法)

SELECT 
    Person_id,
    Store_id,
    MAX(CASE WHEN seq = 1 THEN Startdate END) AS Startdate1,
    MAX(CASE WHEN seq = 1 THEN enddate END) AS enddate1,
    MAX(CASE WHEN seq = 2 THEN Startdate END) AS Startdate2,
    MAX(CASE WHEN seq = 2 THEN enddate END) AS enddate2,
    MAX(CASE WHEN seq = 3 THEN Startdate END) AS Startdate3,
    MAX(CASE WHEN seq = 3 THEN enddate END) AS enddate3,
    MAX(CASE WHEN seq = 4 THEN Startdate END) AS Startdate4,
    MAX(CASE WHEN seq = 4 THEN enddate END) AS enddate4
FROM (
    SELECT 
        Person_id,
        Store_id,
        Startdate,
        enddate,
        ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
    FROM your_table_name
    WHERE Person_id = '10000351067'
) t
GROUP BY Person_id, Store_id;

方式2:使用crosstab函数

需要先安装tablefunc扩展:

-- 先执行安装扩展(只需一次)
CREATE EXTENSION IF NOT EXISTS tablefunc;

SELECT *
FROM crosstab(
    -- 拼接需要转列的数据源
    'SELECT Person_id, Store_id, CONCAT(''Startdate'', seq), Startdate
     FROM (
         SELECT Person_id, Store_id, Startdate,
                ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
         FROM your_table_name
         WHERE Person_id = ''10000351067''
     ) t
     UNION ALL
     SELECT Person_id, Store_id, CONCAT(''enddate'', seq), enddate
     FROM (
         SELECT Person_id, Store_id, enddate,
                ROW_NUMBER() OVER (PARTITION BY Person_id, Store_id ORDER BY Startdate) AS seq
         FROM your_table_name
         WHERE Person_id = ''10000351067''
     ) t
     ORDER BY 1,2,3',
    -- 指定要生成的列名
    'VALUES (''Startdate1''), (''enddate1''), (''Startdate2''), (''enddate2''), (''Startdate3''), (''enddate3''), (''Startdate4''), (''enddate4'')'
) AS ct(Person_id text, Store_id text, Startdate1 date, enddate1 date, Startdate2 date, enddate2 date, Startdate3 date, enddate3 date, Startdate4 date, enddate4 date);

补充说明

如果你的记录数量不固定(比如有的用户有5条,有的只有2条),想要动态生成列的话,需要用动态SQL(比如MySQL的预处理语句、SQL Server的动态字符串拼接、PostgreSQL的PL/pgSQL)。不过如果是已知最多N条记录,静态的条件聚合写法足够简单好用。

内容的提问来源于stack exchange,提问作者red

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:37:18