【问题标题】:Pivot and Cross Apply枢轴和交叉应用
【发布时间】:2019-07-19 06:07:07
【问题描述】:

这个问题都是围绕同一个主题,但有两个场景。

我有一组从 OData 中提取的值。它有一个列,其中包含我想要旋转并连接在一起的变量

    create table xmpltbl
(   [Location]  nvarchar(max),
    [Site]      nvarchar(max),  
    [Variable]  nvarchar(max),  
    [Period]        datetimeoffset(3),  
    [StringValue]   nvarchar(max),
    [NumericValue] decimal(10,2)
);

INSERT INTO xmpltbl
(
    [Location],     
    [Site], 
    [Variable], 
    [Period],   
    [StringValue],
    [NumericValue]
)

VALUES 

('UK','London','Customer1','2019-01-01 00:28:53.897','Company A',NULL),
('UK','London','Product1','2019-01-01 00:28:53.897', 'Sand' ,NULL),
('UK','London','Division1','2019-01-01 00:28:53.897','Supplies',NULL),
('UK','London','Expense1','2019-01-01 00:28:53.897',NULL,150),
('UK','London','Customer2','2019-01-01 00:28:53.897','CompanyB',NULL),
('UK','London','Product2','2019-01-01 00:28:53.897','Bricks',NULL),
('UK','London','Division2','2019-01-01 00:28:53.897','Building Materials',NULL),
('UK','London','Expense2','2019-01-01 00:28:53.897',NULL,300),
('France','Paris','Customer3','2020-01-01 00:28:53.897','Company C',NULL),
('France','Paris','Product3','2020-01-01 00:28:53.897','Cement',NULL),
('France','Paris','Division3','2019-01-01 00:28:53.897','Supplies',NULL),
('France','Paris','Expense3','2019-01-01 00:28:53.897',NULL,75);

我需要具有相同数字的变量位于同一行,并且它们旁边有值。理想情况下,我想用 SSIS 来做这件事,因为我正在使用它来提取数据。

我希望它看起来像这样

Location    Site        Period      Customer    Product     Division        Total
UK       London     2019        CompanyA    Sand        Supplies        150
UK       London     2019        CompanyB    Bricks      Building Materials  300
France      Paris       2020        CompanyC    Cement      Supplies        75

还有一些数据不对应

Customer1 + Product1, Division1, Expense1

并且需要

Customer1 + Product10, Division10, Expense10

Customer1 + Product11, Division11, Expense11

我考虑过使用动态枢轴,因为我需要处理大约 60 个这样的变量。但是这是加入,但我做不到。 我尝试进行 CROSS APPLY,但即使我将其放入临时表中,它也不会给我返回值。

DECLARE  @cols AS NVARCHAR(MAX),
         @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT ',' + QUOTENAME(Variable) 
            FROM xmpltbl
            GROUP BY Variable
            ORDER BY Variable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Location, Site, NumericValue, Period, ' + @cols + ' from 
            (
                select Location
                    , Site
                    , Variable
                    , NumericValue
                    , Period
                    , StringValue


                from xmpltbl
           ) x
            pivot 
            (
                 max(StringValue)
                for Variable in (' + @cols + ')
            ) p '

execute (@query);

【问题讨论】:

  • "不过是加入但我做不到。"加入什么?您的问题中只有一张桌子。请向我们展示您的动态数据透视查询以及结果有什么问题。
  • 是的,有一张桌子,也许应该使用选择而不是加入这个词。所以它最终像上面的 Customer1 + Product1, Division1, Expense1
  • 在那种情况下,我不明白你能做什么和不能做什么。同样,如果您发布您的代码以及结果有什么问题,将会很清楚。
  • 我编辑了帖子并放入了我的动态查询。查询没有问题我只是不知道如何将结果放入Location Site Period Customer Product Division Total
  • 我认为使用子查询或 CTE 比使用动态枢轴更容易,你得到了一个很好的答案。你试过了吗??

标签: sql sql-server tsql ssis odata


【解决方案1】:

我不知道这是否是使用 SQL 执行此操作的最佳方法,但以下解决方案给出了预期的结果:

导入临时表

我使用以下查询将数据导入临时表:

create table #xmpltbl
(   [Location]  nvarchar(max),
    [Site]      nvarchar(max),  
    [Variable]  nvarchar(max),  
    [Period]        datetimeoffset(3),  
    [StringValue]   nvarchar(max),
    [NumericValue] decimal(10,2)
);

INSERT INTO #xmpltbl
(
    [Location],     
    [Site], 
    [Variable], 
    [Period],   
    [StringValue],
    [NumericValue]
)

VALUES 

('UK','London','Customer1','2019-01-01 00:28:53.897','Company A',NULL),
('UK','London','Product1','2019-01-01 00:28:53.897', 'Sand' ,NULL),
('UK','London','Division1','2019-01-01 00:28:53.897','Supplies',NULL),
('UK','London','Expense1','2019-01-01 00:28:53.897',NULL,150),
('UK','London','Customer2','2019-01-01 00:28:53.897','CompanyB',NULL),
('UK','London','Product2','2019-01-01 00:28:53.897','Bricks',NULL),
('UK','London','Division2','2019-01-01 00:28:53.897','Building Materials',NULL),
('UK','London','Expense2','2019-01-01 00:28:53.897',NULL,300),
('France','Paris','Customer3','2020-01-01 00:28:53.897','Company C',NULL),
('France','Paris','Product3','2020-01-01 00:28:53.897','Cement',NULL),
('France','Paris','Division3','2019-01-01 00:28:53.897','Supplies',NULL),
('France','Paris','Expense3','2019-01-01 00:28:53.897',NULL,75);

使用公用表表达式获得所需的输出

我使用公用表表达式 (CTE) 来构建查询:

WITH CTE_1 AS (SELECT *, (ROW_NUMBER() OVER(ORDER BY [Location],     
               [Site] ) - 1) / 4 as grpno FROM #xmpltbl), 
     CTE_2 AS (SELECT * , ROW_NUMBER() OVER(PARTITION BY grpno ORDER BY grpno) rn 
               FROM CTE_1),
     CTE_3 AS (SELECT *, case when rn = 2 Then 1 else 0 end as Product, case when rn = 3 Then 1 else 0 end as Supplies
               FROM CTE_2)
SELECT DISTINCT [Location], [Site], Year([Period]) as [Period], 
                FIRST_VALUE(StringValue) OVER(PARTITION BY grpno ORDER BY rn) as [Customer] ,
                FIRST_VALUE(StringValue) OVER(PARTITION BY grpno ORDER BY Product DESC) as [Product] ,
                FIRST_VALUE(StringValue) OVER(PARTITION BY grpno ORDER BY Supplies DESC) as [Supplies] ,
                MAX([NumericValue]) OVER(PARTITION BY grpno) as [Total] 
from CTE_3

输出


旁注:此解决方案仅适用于 SQL Server 2012 或更高版本,因为它利用 FIRST_VALUE() 窗口函数 which is added in SQL Server 2012

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2021-09-10
    • 1970-01-01
    相关资源
    最近更新 更多