SQL将所有列和行转移到单行

时间:2015-05-28 15:57:25

标签: sql sql-server

我在Stack Overflow和网页上搜索了一个我需要做的例子,似乎无法弄清楚如何应用旋转来完成我需要做的事情。也许使用Pivot根本就不是正确的答案,但似乎我缺乏理解可能会妨碍。我有一个表格,其数据如下所示:

year    property type   market total    taxable total   parcel count
----    -------------   ------------    -------------   ------------
2012    Real            23453           34563           123
2012    Personal        53434           65432           321
2013    Real            24565           23546           345
2013    Personal        64453           45636           342
2014    Real            76586           78645           876
2014    Personal        56775           67556           897

我需要把它变成一个结果,将所有值显示为每年一行,如下所示:

year real market real taxable real count pers market pers taxable pers count
---- ----------- ------------ ---------- ----------- ------------ ----------
2012 23453       34563        123        53434       65432        321
2013 24565       23546        345        64453       45636        342
2014 76586       78645        876        56775       67556        897

我看到的所有数据透视表示例都将列名称显示为源数据中列的实际值,这对我来说似乎并非如此。而我无法动态构建SQL。顺便说一下,“属性类型”值是一个已知的集合,所以我确切知道输出所需的列数。

以简单的方式在SQL中执行此操作吗?它似乎应该是......

4 个答案:

答案 0 :(得分:1)

我不确定您使用的DBMS,但我相信我的查询应该适合您(我使用的是SQL Server)。

我的桌子版本

DECLARE @yourTable TABLE ([year] INT,[Property Type] VARCHAR(20),[Market Total] INT,[Taxable Total] INT,[Parcel Count] INT);
INSERT INTO @yourTable
VALUES  (2012,'Real',23453,34563,123),
        (2012,'Personal',53434,65432,321),
        (2013,'Real',24565,23546,345),
        (2013,'Personal',64453,45636,342),
        (2014,'Real',76586,78645,876),
        (2014,'Personal',56775,67556,897);

实际查询

SELECT  [year],
        MAX(CASE WHEN [Property Type] = 'Real' THEN [Market Total]  END) AS [Real Market],
        MAX(CASE WHEN [Property Type] = 'Real' THEN [Taxable Total] END) AS [Real Taxable],
        MAX(CASE WHEN [Property Type] = 'Real' THEN [Parcel Count]  END) AS [Real Count],

        MAX(CASE WHEN [Property Type] = 'Personal' THEN [Market Total]  END) AS [Personal Market],
        MAX(CASE WHEN [Property Type] = 'Personal' THEN [Taxable Total] END) AS [Personal Taxable],
        MAX(CASE WHEN [Property Type] = 'Personal' THEN [Parcel Count]  END) AS [Personal Count]
FROM @yourTable
GROUP BY [year]

答案 1 :(得分:0)

您可以使用INNER JOIN查询来实现结果:

这是MySQL语法:

SELECT t1x.`year`, `real market`, `real taxable`, `real count`,
       `pers market`, `pers taxable`, `pers count`
FROM (SELECT `year`, `market total` AS `real market`, 
         `taxable total` AS `real taxable`, `parcel count` AS `real count`
     FROM t1
     WHERE `property type` = 'Real') t1x
INNER JOIN (SELECT `year`, `market total` AS `pers market`, 
            `taxable total` AS `pers taxable`, `parcel count` AS `pers count`
            FROM t1
            WHERE `property type` = 'Personal') t1y
ON t1x.`year` = t1y.`year`

以下是SQL Fiddle,因此您可以了解它是如何运作的。

基本上,您可以从表中选择值(我称之为 t1 )为两个临时表 t1x t1y 。在 t1x 表格中,您可以选择 t1 行,其中属性类型列值真实并进入 t1y < / strong>该值个人。并且在列中加入两个表...

SQL Server语法几乎相同,唯一的区别在于它们如何处理MySQL中的两个单词列我们使用后引用(`)而在SQL Server中我们使用这样的括号[];

这里的语法如下:

SELECT t1x.[year], [real market], [real taxable], [real count],
       [pers market], [pers taxable], [pers count]
FROM (SELECT [year], [market total] AS [real market], 
             [taxable total] AS [real taxable], [parcel count] AS [real count]
     FROM t3
     WHERE [property type] = 'Real')AS t1x
INNER JOIN (SELECT [year], [market total] AS [pers market], 
            [taxable total] AS [pers taxable], [parcel count] AS [pers count]
            FROM t1
            WHERE [property type] = 'Personal') t1y
ON t1x.[year] = t1y.[year]

如果你使用任何其他数据库,至少你知道如何处理这个问题......

GL!

答案 2 :(得分:0)

我需要报告的数据经常出现相同类型的问题,我使用了这两个选项并查看了性能问题,以帮助我选择在给定报告中使用的选项。通常我会将最小的结果数据推送到临时表,然后进行最终的操作以进行报告。这样可以减少I / O负载。

IF OBJECT_ID('tempdb..#SAMPLEDATA') IS NOT NULL DROP TABLE #SAMPLEDATA; 
CREATE TABLE #SAMPLEDATA
(
    [Year] INT,
    [Property Type] VARCHAR(50),
    [Market] DECIMAL(18,2),
    [Taxable] DECIMAL(18,2),
    [Parcel] INT
)


INSERT INTO #SAMPLEDATA([Year],[Property Type],[Market],[Taxable],[Parcel]) VALUES
    (2012,'Real',23453,34563,123),
    (2012,'Personal',53434,65432,321),
    (2013,'Real',24565,23546,345),
    (2013,'Personal',64453,45636,342),
    (2014,'Real',76586,78645,876),
    (2014,'Personal',56775,67556,897)

-- OPTION 1 (LINKING MULTIPLE PIVIOTS) -- DOWNSIDE -- HITTING THE DATA NUMBEROUS TIMES HIGH I/O

SELECT 
    L.[Year],
    D1.[real market],
    D2.[real taxable],
    D3.[real count],
    D1.[pers market],
    D2.[pers taxable],
    D3.[pers count]
FROM
    (SELECT [YEAR] FROM #SAMPLEDATA GROUP BY [YEAR]) AS L
    LEFT OUTER JOIN (SELECT [Year],[Real] AS [real market],[Personal] AS [pers market] FROM (SELECT [Year],[Property Type],[Market] FROM #SAMPLEDATA) AS P1 PIVOT (SUM([Market]) FOR [Property Type] IN ([Real],[Personal])) AS DATA1) AS D1
        ON L.[Year] = D1.[Year]
    LEFT OUTER JOIN (SELECT [Year],[Real] AS [real taxable],[Personal] AS [pers taxable] FROM (SELECT [Year],[Property Type],[Taxable] FROM #SAMPLEDATA) AS P2 PIVOT (SUM([Taxable]) FOR [Property Type] IN ([Real],[Personal])) AS DATA2) AS D2
        ON L.[Year] = D2.[Year]
    LEFT OUTER JOIN (SELECT [Year],[Real] AS [real count],[Personal] AS [pers count] FROM (SELECT [Year],[Property Type],[Parcel] FROM #SAMPLEDATA) AS P3 PIVOT (SUM([Parcel]) FOR [Property Type] IN ([Real],[Personal])) AS DATA3) AS D3
        ON L.[Year] = D3.[Year]

-- OPTION 2 (CASE SUMS)
    SELECT 
    [Year],
    SUM (CASE WHEN [Property Type] = 'Real' THEN [Market] ELSE 0 END) AS [real market],
    SUM (CASE WHEN [Property Type] = 'Real' THEN [Taxable] ELSE 0 END) AS [real taxable],
    SUM (CASE WHEN [Property Type] = 'Real' THEN [Parcel] ELSE 0 END) AS [real count],
    SUM (CASE WHEN [Property Type] = 'Personal' THEN [Market] ELSE 0 END) AS [pers market],
    SUM (CASE WHEN [Property Type] = 'Personal' THEN [Taxable] ELSE 0 END) AS [pers taxable],
    SUM (CASE WHEN [Property Type] = 'Personal' THEN [Parcel] ELSE 0 END) AS [pers count]
    FROM 
    #SAMPLEDATA
GROUP BY
    [Year]

答案 3 :(得分:0)

经过大量的反复试验并查看其他示例后,我终于想出了一种使用PIVOT操作的方法。我想使用数据透视而不是上述解决方案的原因是因为我必须查询的真实数据超过20&#34;属性类型&#34;每个&#34;属性类型&#34;有4个值,这使得解决问题成为一个怪物,但......这是我能够提出的枢纽解决方案:

with sample_data([year], [property_type], [market_total], [taxable_total], [parcel_count])
as
(
          select 2012, 'Real', 23453, 34563, 123
    union select 2012, 'Personal', 53434, 65432, 321
    union select 2013, 'Real', 24565, 23546, 345
    union select 2013, 'Personal', 64453, 45636, 342
    union select 2014, 'Real', 76586, 78645, 876
    union select 2014, 'Personal', 56775, 67556, 897
),
categorized_data ([year], [column_name], [column_value])
as
(
    select [year], [property_type] + '_market_total', [market_total] from sample_data
    union select [year], [property_type] + '_taxable_total', [taxable_total] from sample_data
    union select [year], [property_type] + '_parcel_count', [parcel_count] from sample_data
)
select * from categorized_data
pivot
(
    max(column_value) for column_name in 
    (
        [Real_market_total], 
        [Real_taxable_total], 
        [Real_parcel_count], 
        [Personal_market_total], 
        [Personal_taxable_total], 
        [Personal_parcel_count]
    )
) as pvt

希望这会帮助那些一开始就像我一样难过的人。