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

动态列下CHECK_CARD表Unpivot报错:SELECT关键字语法错误求助

动态SQL实现CHECK_CARD表转置的问题解决

需求回顾

你需要转置CHECK_CARD表,原表结构如下:

anc_report_dateRiskSignalgroup_company_attr
2019-01-01 00:00:00.0000000NoRiskSignal4894543
2016-07-01 00:00:00.0000000RiskSignal1242151

期望转换为:

anc_report_date2019-01-01 00:00:00.00000002016-07-01 00:00:00.0000000
RiskSignalNoRiskSignalRiskSignal
group_company_attr48945431242151

问题分析

你之前的代码报错核心原因是直接把SELECT查询语句拼到了UNPIVOT的IN子句里——UNPIVOT要求IN子句里是明确的列名/值列表,不能嵌套查询。从你PRINT出的SQL就能看到,IN里直接塞了一整段SELECT逻辑,这必然触发语法错误。

正确解决方案

要实现动态转置,我们需要分两步处理:

  1. 先把需要作为列的所有日期值,拼接成带引号、逗号分隔的字符串列表
  2. 结合UNPIVOT和PIVOT完成行转列操作(先把原表的列转成行,再把日期行转成列)

以下是完整的可执行代码:

-- 第一步:获取所有需要作为列的日期,拼接成带QUOTENAME的字符串列表
DECLARE @Column NVARCHAR(MAX);

-- SQL Server 2017及以上版本用STRING_AGG(更简洁)
SELECT @Column = STRING_AGG(QUOTENAME(anc_report_date), ', ')
FROM (
    SELECT DISTINCT cc.anc_report_date 
    FROM CHECK_CARD cc 
    INNER JOIN CHECK_CARD chc 
        ON cc.group_company_attr = chc.group_company_attr 
        AND cc.anc_report_date <= chc.anc_report_date 
        AND chc.id = 1832307 
    WHERE cc.status = 1
) AS Dates;

-- 如果是SQL Server 2016及以下版本,用FOR XML PATH做兼容拼接
/*
SELECT @Column = STUFF((
    SELECT ', ' + QUOTENAME(anc_report_date)
    FROM (
        SELECT DISTINCT cc.anc_report_date 
        FROM CHECK_CARD cc 
        INNER JOIN CHECK_CARD chc 
            ON cc.group_company_attr = chc.group_company_attr 
            AND cc.anc_report_date <= chc.anc_report_date 
            AND chc.id = 1832307 
        WHERE cc.status = 1
    ) AS Dates
    FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '');
*/

-- 第二步:构建动态转置SQL并执行
DECLARE @Transpose NVARCHAR(MAX);
SET @Transpose = N'
SELECT *
FROM (
    -- UNPIVOT:把原表的RiskSignal、group_company_attr转成属性名+属性值的行
    SELECT 
        anc_report_date,
        attribute_name,
        attribute_value
    FROM CHECK_CARD
    UNPIVOT (
        attribute_value FOR attribute_name IN (RiskSignal, group_company_attr)
    ) AS unpvt
) AS src
-- PIVOT:把不同的anc_report_date转成列,用MAX取唯一值(因为每个组合只有一个值)
PIVOT (
    MAX(attribute_value) FOR anc_report_date IN (' + @Column + ')
) AS pvt;
';

EXEC sp_executesql @Transpose;

代码解释

  1. 拼接日期列表:用STRING_AGG(或兼容旧版本的FOR XML PATH)把查询到的日期转换成[2019-01-01 00:00:00.0000000], [2016-07-01 00:00:00.0000000]格式,QUOTENAME用于包裹日期,避免特殊字符导致语法错误。
  2. UNPIVOT阶段:把原表中RiskSignal和group_company_attr两列转成两行数据,每行包含日期、属性名(比如"RiskSignal")和属性值(比如"NoRiskSignal")。
  3. PIVOT阶段:把不同的日期值转成列,用MAX聚合函数是因为每个属性名+日期的组合只有唯一值,MAX不会改变结果,只是满足PIVOT对聚合函数的强制要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:04:43