sql - 透视和交叉应用

标签 sql sql-server tsql ssis odata

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

我有一组从 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);

最佳答案

我不知道这是否是使用 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

输出

enter image description here


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

关于sql - 透视和交叉应用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54872945/

相关文章:

python - 无法在事务中执行备份或还原操作

php - MySQL 外键约束不被尊重/遵守

ios - Azure 移动服务自定义 API 多次调用 SQL SP

c# - 使用 ado.net 获取身份的 OUTPUT 子句示例?

SQL查询选择帮助需要

sql - 如何在SQL中分组并选择最小值

sql - 如何比较两个 SQL 查询以在 Postgres 上运行

javascript - 意外的 token 导出异步函数

sql-server - 如何在 T-SQL 中重新创建 InitCap() 函数以将首字母大写应用于字符串?

MySQL:为什么这些查询返回不同的结果?