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

SQL Server 2016:将多行数据按不同迭代转换为列

嘿,这个需求就是典型的**行转列(Pivot)**场景,我给你整理了几个常用数据库的实现方案,直接套用就行~

先明确下需求的前后对比,方便你对应:

原表结构示例:

MemberIDInsuranceNo
1INS001
1INS002
2INS003

期望结果:

MemberIDInsuranceNo1InsuranceNo2
1INS001INS002
2INS003NULL

1. SQL Server 用内置 PIVOT 函数

SQL Server自带的PIVOT语法很适合这种场景,先给每个MemberID下的InsuranceNo编序号,再转成列:

-- 先给每个MemberID的InsuranceNo生成唯一序号
WITH RankedIns AS (
    SELECT 
        MemberID,
        InsuranceNo,
        -- 生成列名:InsuranceNo1、InsuranceNo2...
        'InsuranceNo' + CAST(ROW_NUMBER() OVER (PARTITION BY MemberID ORDER BY InsuranceNo) AS VARCHAR(10)) AS ColName
    FROM YourTableName -- 替换成你的表名
)
-- 用PIVOT转成列格式
SELECT 
    MemberID,
    -- 用ISNULL把空值换成你需要的默认值,比如空字符串
    ISNULL([InsuranceNo1], '') AS InsuranceNo1,
    ISNULL([InsuranceNo2], '') AS InsuranceNo2,
    ISNULL([InsuranceNo3], '') AS InsuranceNo3 -- 按需增加更多列
FROM RankedIns
PIVOT (
    MAX(InsuranceNo) -- 聚合函数选MAX/ MIN都可以,因为每个序号对应唯一值
    FOR ColName IN ([InsuranceNo1], [InsuranceNo2], [InsuranceNo3])
) AS PivotTable;

如果不确定最多有多少个InsuranceNo,可以用动态SQL自动生成列,避免手动加列的麻烦。


2. MySQL 两种实现方式

MySQL没有内置PIVOT,不过可以用字符串拼接拆分,或者动态SQL来搞定:

方法一:静态列(已知最多InsuranceNo数量)

适合你能确定每个MemberID最多有几个InsuranceNo的情况:

SELECT 
    MemberID,
    -- 拆分出第1个InsuranceNo
    SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(InsuranceNo ORDER BY InsuranceNo), ',', 1), ',', -1) AS InsuranceNo1,
    -- 拆分出第2个InsuranceNo
    SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(InsuranceNo ORDER BY InsuranceNo), ',', 2), ',', -1) AS InsuranceNo2,
    -- 按需增加更多列
    SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(InsuranceNo ORDER BY InsuranceNo), ',', 3), ',', -1) AS InsuranceNo3
FROM YourTableName
GROUP BY MemberID;

原理是先用GROUP_CONCAT把同一个MemberID的InsuranceNo拼成逗号分隔的字符串,再用SUBSTRING_INDEX拆分出对应位置的值。

方法二:动态SQL(自动适配最多列数)

如果InsuranceNo的数量不确定,用动态SQL自动生成所有需要的列:

SET @sql = NULL;
-- 生成所有拆分列的SQL语句
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(InsuranceNo ORDER BY InsuranceNo), '','', ', n, '), '','', -1) AS InsuranceNo', n
    )
  ) INTO @sql
FROM (
  -- 找出最多有多少个InsuranceNo,生成对应的序号
  SELECT ROW_NUMBER() OVER () AS n
  FROM YourTableName
  GROUP BY MemberID
  HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) AS cnt FROM YourTableName GROUP BY MemberID) t)
) t;

-- 拼接完整的查询语句
SET @sql = CONCAT('SELECT MemberID, ', @sql, ' FROM YourTableName GROUP BY MemberID');

-- 执行动态SQL
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

3. PostgreSQL 用 crosstab 函数

PostgreSQL需要先启用tablefunc扩展,然后用crosstab实现行转列:

-- 先启用tablefunc扩展(如果还没启用)
CREATE EXTENSION IF NOT EXISTS tablefunc;

-- 执行行转列查询
SELECT 
    MemberID,
    "1" AS InsuranceNo1,
    "2" AS InsuranceNo2,
    "3" AS InsuranceNo3 -- 按需增加列
FROM crosstab(
    -- 第一个参数:带序号的源数据查询
    'SELECT MemberID, ROW_NUMBER() OVER (PARTITION BY MemberID ORDER BY InsuranceNo), InsuranceNo FROM YourTableName ORDER BY 1,2',
    -- 第二个参数:列的序号范围(这里的3替换成实际最多的InsuranceNo数量)
    'SELECT generate_series(1,3)'
) AS ct(MemberID INT, InsuranceNo1 VARCHAR(50), InsuranceNo2 VARCHAR(50), InsuranceNo3 VARCHAR(50));

小提示:如果你的业务中InsuranceNo的数量经常变化,优先选动态SQL方案;如果数量固定,静态查询更简单高效~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 06:58:21