T-SQL 旋转表

T-SQL rotating table

提问人:user3248518 提问时间:11/13/2023 最后编辑:Joel Coehoornuser3248518 更新时间:11/14/2023 访问量:50

问:

我有一张表格如下:

组织机构代码 先决条件名称 先决条件值 言论
AFA(阿法协会) 聚氯乙烯 1
AFA(阿法协会) 责任 1

我需要一个这样的结果表:

组织机构代码 IsPpco公司 PPCO备注 IsLiability (责任) 责任备注
AFA(阿法协会)

我可以在 SQL Server 中使用什么运算符来实现此结果?

sql sql-server t-sql

评论

1赞 Panagiotis Kanavos 11/13/2023
在 SQL(语言)中,这称为旋转,而不是旋转。检查 PIVOT 和 UNPIVOT 命令
1赞 Joel Coehoorn 11/14/2023
这看起来有点像 EAV 反模式。

答:

0赞 Xedni 11/13/2023 #1

通常有两种方法可以做到这一点:您可以使用实际运算符,或者使用类似的东西(这通常称为“交叉表枢轴”;我想,如果我错了,有人会纠正我,我可能在这里使用了错误的术语)。我发现后一种方法通常更容易推理,因为枢轴语法不是很直接。在这种情况下,这一点更为重要,因为您希望从列中透视值。PIVOTMAX

这个想法是你检查这个名字是否是你想要的,如果是,你就投射它的价值。否则,您将投射 .运算符将为与约束匹配的行选取所需的值,并且 null 值将从查询中消失:PrereqnullMAXIIF

;with a (OrgCode, PrereqName, PrereqValue, Remarks) as
(
    select 'AFA', 'ppco', 1, cast(null as varchar(100)) union all
    select 'AFA', 'liability', 1, null 
), b as
(
    select
        OrgCode,
        IsPpco = max(iif(PrereqName = 'ppco', PrereqValue, null)),
        IsLiability = max(iif(PrereqName = 'liability', PrereqValue, null)),
        LiabilityRemarks = max(iif(PrereqName = 'liability', Remarks, null))
    from a
    group by OrgCode
)
select
    OrgCode,
    IsPpco = iif(IsPpco = 1, 'True', 'False'),
    IsLiability = iif(IsLiability = 1, 'True', 'False'),
    LiabilityRemarks
from b
1赞 Alex 11/14/2023 #2

小心使用 PIVOT,即使您不选择某些列,它也会按表上的所有内容进行分组。如有必要,请在 PIVOTING 之前使用 CTE。例如,在这里,它将对包括 PrerequisitesValue 在内的所有内容进行分组

DECLARE @t TABLE 
(
    OrganizationCode VARCHAR(3),
    PrerequisitesName VARCHAR(20), 
    PrerequisitesValue INT, 
    Remarks VARCHAR(20)
);

INSERT INTO @t VALUES('AFA', 'ppco',1, null);
INSERT INTO @t VALUES('AFA', 'liability',1, null);
INSERT INTO @t VALUES('XYZ', 'ppco',1, 'ppcoRemark');
INSERT INTO @t VALUES('ABC', 'liability',1, 'liabilityRemark');

SELECT 
    pvt.OrganizationCode,
    CASE WHEN pvt.ppco > 0 THEN 'True' ELSE 'False' end IsPpco,
    CASE WHEN pvt.ppco > 0 THEN pvt.Remarks END AS PpcoRemarks,
    CASE WHEN pvt.[liability] > 0 THEN 'True' ELSE 'False' END IsLiability,
    CASE WHEN pvt.[liability] > 0 THEN pvt.Remarks END AS LiabilityRemarks
FROM 
    @t t PIVOT (COUNT(PrerequisitesName) FOR PrerequisitesName IN ([liability],[ppco])) AS pvt;