【问题标题】:SQL Pivot Table Not Putting Results In One LineSQL 数据透视表没有将结果放在一行中
【发布时间】:2019-03-26 18:13:56
【问题描述】:

我正在尝试在 SQL 中创建数据透视表。我的结果并没有像我希望的那样合并到每个 TID 的一行中。这个例子应该让我的问题清楚:

    Results:

    TID NS_AM   AS_AM   NS_DB   AS_DB
    TID 1a  971     947     
    TID 2   807     974     
    TID 1a                  954     910
    TID 2                   931     904


    Desired Results:

    TID     NS_AM   AS_AM   NS_DB   AS_DB
    TID 1a  971     947     954     910
    TID 2   807     974     931     904 

编辑:这是从大型动态查询派生的。我无法输入该查询,因为它会使问题变得非常混乱。我必须使用枢轴/取消枢轴。

任何帮助将不胜感激。下面是示例数据和生成我的结果的查询。

如您所见,AM 项目被合并到一行,DB 项目被合并到一行,但它们并没有像我希望的那样报告所有结果。

            drop table if exists  mock_data;
             create table MOCK_DATA (
                tid VARCHAR(50),
                plantype VARCHAR(50),
                ns VARCHAR(50),
                [as] VARCHAR(50)
            );
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '112', '048');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '142', '889');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '887', '668');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '093', '910');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '954', '266');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'DB', '822', '201');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '234', '083');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '527', '716');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '662', '168');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '795', '947');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '971', '588');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '755', '234');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '199', '603');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '164', '362');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '943', '462');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '971', '164');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '594', '822');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '467', '478');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '064', '591');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 1a', 'AM', '639', '298');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '186', '797');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '226', '369');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '036', '272');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '807', '197');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '167', '402');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '477', '047');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '262', '974');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '268', '282');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'AM', '508', '069');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '303', '528');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '747', '325');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '293', '614');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '886', '221');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '652', '365');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '931', '904');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '089', '662');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '922', '497');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '722', '328');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '386', '324');
            insert into MOCK_DATA (tid, plantype, ns, [as]) values ('TID 2', 'DB', '402', '552');



            SELECT [TID],
                   IsNull([NS_AM], '') AS [NS_AM],
                   IsNull([AS_AM], '') AS [AS_AM] 
            FROM
            (
                SELECT [TID],
                       [PlanType],
                       col+'_'+CAST(PlanType AS VARCHAR(50)) col,
                       value
                FROM
            (
                SELECT PlanType,
                       [TID],
                       CAST(NS AS VARCHAR(100)) AS NS,
                       CAST(AS AS VARCHAR(100)) AS AS 

                FROM #temp
            ) s UNPIVOT(value FOR col IN(NS,
                                         AS )) unpiv
            ) src PIVOT(MAX(value) FOR col IN([NS_AM],
                                              [AS_AM], 
                                              [NS_DB],
                                              [AS_DB] 

             )) p; 

提前非常感谢您。

【问题讨论】:

    标签: sql sql-server pivot unpivot


    【解决方案1】:

    使用 CROSS TABS 而不是取消透视和透视数据,这可能非常简单。

    SELECT TID, 
           MAX( CASE WHEN PlanType = 'AM' THEN [ns] END) AS NS_AM,
           MAX( CASE WHEN PlanType = 'AM' THEN [as] END) AS AS_AM,
           MAX( CASE WHEN PlanType = 'DB' THEN [ns] END) AS NS_DB,
           MAX( CASE WHEN PlanType = 'DB' THEN [as] END) AS AS_DB
    FROM MOCK_DATA
    GROUP BY TID;
    

    如果你想使用动态代码,转换起来并不难。对于您需要处理的每一列,这只是一个复制粘贴编辑的问题,并且代码将根据需要为 plantype 添加尽可能多的值。

    DECLARE @SQL nvarchar(MAX)
    
    SELECT @SQL = N'SELECT TID' + CHAR(10) 
                + ( SELECT DISTINCT REPLACE( REPLACE(
                            CHAR(9) + ',MAX( CASE WHEN PlanType = <<quotedplantype>> THEN [ns] END) AS NS_<<plantype>>' + CHAR(10)
                          + CHAR(9) + ',MAX( CASE WHEN PlanType = <<quotedplantype>> THEN [as] END) AS AS_<<plantype>>' + CHAR(10)
                            , '<<quotedplantype>>', QUOTENAME(plantype, '''')), '<<plantype>>', plantype)
                FROM MOCK_DATA
                FOR XML PATH(''), TYPE).value('./text()[1]', 'varchar(max)') + 
               + N'FROM MOCK_DATA' + NCHAR(10)
               + N'GROUP BY TID;'
    
    EXEC sp_executesql @SQL /*, @params_def, @param1, @param2,..., @paramN*/;
    

    【讨论】:

    • 我知道你是对的,但这是我为了创建这个问题而剥离的动态查询。我肯定会先去那里。谢谢。
    • 这也可以通过动态方式完成。但我猜不出你的需求。我将编辑这篇文章以添加动态选项。
    • 谢谢你,路易斯。有比 NS 和 AS 更多的列以及更多 AM 和 DB 的选项,这就是为什么我在这里使用这个想法 stackoverflow.com/questions/15081290/… 但它对我不起作用。
    • 希望通过编辑,你能真正得到你需要的结果。
    • 谢谢你,路易斯。我不敢相信这行得通。我很感激不仅能解决我的问题,还能教我这条新途径。如此简单的枢轴非枢轴之谜。很高兴您已解决:)
    【解决方案2】:

    尝试在您的 PIVOT/UNPIVOT 表达式中添加“按 TID 排序”。

    【讨论】:

    【解决方案3】:

    Null 被用作替代品(作为一些缺失值的大随机数),这也是它如此独特的原因。但是在这里,聚合函数确实会忽略除计数之外的空值,尽管您也可以同时使用 min 和 max 进行检查

    如果根据我的假设只有空值与上述不同,您可以使用group by 并使用min/max

      Select TID, min(NS_AM),  min( AS_AM),   
       min(NS_DB),  min(AS_DB) Group by 
        TID.     
    

    【讨论】:

    【解决方案4】:

    您可以通过如下进行内部连接来获取所需的数据,无需枢轴!

    select v1.tid,v1.m_ns[Ns_Am],v1.m_as[As_Am],v2.m_ns[NS_DB],V2.m_As[AS_DB] from(
    select tid,plantype,max(ns)[m_ns],max([as]) [m_as]  from MOCK_DATA group by tid,plantype) v1
    inner join
    (select tid,plantype,max(ns)[m_ns],max([as]) [m_as]  from MOCK_DATA group by tid,plantype)v2
    on v1.tid=v2.tid and v1.plantype='Am' and  v2.plantype='DB' 
    

    你也可以使用这个你可以动态的脚本(给我一些时间,我会为你做的!)

    select v1.tid,v1.[am] [ns_am],v1.[db][ns_db],v2.[am] [as_am],v2.[db][as_db] from
    (select * from(
    select tid,ns,[PlanType] from MOCK_DATA) s
    pivot
    (max(ns) for [PlanType] in ([AM],[DB])  )s
    ) v1
    inner join
    (
    select * from(
    select tid,[as],[PlanType] from MOCK_DATA) s
    pivot
    (max([as]) for [PlanType] in ([AM],[DB])  )s) v2
    
    on v1.tid=v2.tid
    

    【讨论】:

    • 谢谢,但我不能。查询是动态生成的,并且有许多列和计划类型的可能性。不过谢谢。
    • 凯马尔——不要。我真的很感谢你,但我的剧本很笨拙。连接的数量必须是动态的。我认为枢轴/非枢轴是唯一的出路。我为你的努力投了赞成票。
    • 小姐,有一种方法可以在不连接的情况下动态执行此操作,使用光标,如果您愿意,我会发布脚本。
    【解决方案5】:

    这是一个承诺的动态解决方案,使用游标,而不是连接 它将动态列添加到最终表并更新游标循环内的数据

    IF EXISTS(SELECT 1 FROM sysobjects where name='myMOCK_DATA') drop table myMOCK_DATA
    create table myMOCK_DATA (tid varchar(10));insert into  myMOCK_DATA(tid) select distinct(tid) from MOCK_DATA
    declare mycursor cursor for
    select tid,plantype,max(ns)[m_ns],max([as])[m_as] from MOCK_DATA group by tid,plantype
    declare @plantype as varchar(2);declare @tid as varchar(10);declare @m_ns as int;declare @m_as as int
    declare @script as varchar(max);open mycursor
    fetch mycursor into @tid,@plantype,@m_ns,@m_as
    while @@fetch_status=0
    begin
    set @script='IF not EXISTS(SELECT 1 FROM sys.columns  WHERE Name = ''NS_'+@plantype +''' AND Object_ID = Object_ID(N''myMOCK_DATA''))
    BEGIN
        alter table myMOCK_DATA add NS_'+@plantype +' integer
    END'
    print @script;exec(@script)
    set @script='IF not EXISTS(SELECT 1 FROM sys.columns 
              WHERE Name = ''AS_'+@plantype + ''' AND Object_ID = Object_ID(N''myMOCK_DATA''))
    BEGIN
        alter table myMOCK_DATA add AS_'+@plantype +' integer
    END'
    print @script;exec(@script)
    set @script='update myMOCK_DATA set NS_'+@plantype+'='+convert(varchar(10),@m_ns)+ ' where tid='''+@tid+''''
    print @script;exec(@script)
    set @script='update myMOCK_DATA set AS_'+@plantype+'='+convert(varchar(10),@m_as)+ ' where tid='''+@tid+''''
    print @script;exec(@script)
    fetch mycursor into @tid,@plantype,@m_ns,@m_as
    end
    close mycursor
    deallocate mycursor
    select * from myMOCK_DATA
    

    【讨论】:

    • 非常感谢凯末尔。我用它做了一点,它可以工作。问题是我拥有的数据量太慢了。为我的 > 300,000 行获取并可能更改表真的让我想尝试找到一种方法来让我的原始解决方案正常工作。并不是我不欣赏这项工作,而且您肯定找到了一个聪明的方法——我现在不能用它来解决这个问题。谢谢,我的朋友。我会查看你的个人资料并为你的努力点赞。
    【解决方案6】:

    尝试只选择需要的列来生成标题:

    SELECT   [1]
         ,   [2]
         ,   [3]
         ,   [4]
         ,   [5]
         FROM (SELECT klassID, KlassText FROM tblKlass) s
         PIVOT (
             MAX(KlassText) 
             FOR klassID IN ([1], [2], [3], [4], [5])
         ) p
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-08
      • 1970-01-01
      • 2012-03-12
      • 2016-06-30
      • 1970-01-01
      相关资源
      最近更新 更多