将多行/列旋转为1行

时间:2019-06-19 22:29:38

标签: sql pivot multiple-columns rows

我们需要采用多行多列并将其转换为每个键1行。我有一个数据透视查询,但是不起作用。我收到一些有关“列定义不明确”的错误

我们的数据如下:

SECTOR   TICKER  COMPANY
-----------------------------------------------------
5         ADNT    Adient PLC
5         AUTO    Autobytel Inc.
5         THRM    Gentherm Inc
5         ALSN    Allison Transmission Holdings, Inc.
5         ALV     Autoliv, Inc.
12        HES     Hess Corporation
12        AM      Antero Midstrm
12        PHX     Panhandle Royalty Company
12        NBR     Nabors Industries Ltd.
12        AMRC     Ameresco, Inc.

我们需要的是每个ID 1行,每个TICKER / COMPANY在不同的列中。因此,输出如下所示:

5 ADNT   Adient PLC   AUTO  Autobytel Inc.   THRM  Gentherm Inc........

您明白了。每个ID 1行,彼此对应的值在其自己的列中。我尝试过的查询是:

SELECT sector, ticker, company_name
FROM (SELECT d.sector, d.ticker, v.company_name, ROW_NUMBER() OVER(PARTITION BY d.sector ORDER BY d.sector) rn
           FROM template13_ticker_data d, template13_vw v
           WHERE d.m_ticker = v.m_ticker) 
PIVOT (MAX(sector) AS sector, MAX(ticker) AS ticker, MAX(company_name) AS company_name
 FOR (rn) IN (1 AS sector, 2 AS ticker, 3 AS company_name))
ORDER BY sector;

1 个答案:

答案 0 :(得分:0)

首先要了解数据透视,您需要在结果集中选择一个列作为PIVOT锚点,数据将围绕数据透视旋转,这在{{1 }}子句。

  

您只能FOR PIVOT的一列,但是您可以在子查询中或根据联接或视图构造此列,作为您的目标数据查询, OP FOR,但您可以使用任何希望的SQL机制,甚至可以使用ROW_NUMBER()语句来构建自定义列,以便在数据集中没有自然列要使用时进行旋转。

CASE将为PIVOT列中的每个 value 列创建一列,并为该列提供您所使用的聚合函数的值指定

它有助于可视化构造的记录集,在应用数据透视表之前,以下SQL可以重新创建OP呈现的数据方案。我在这里使用表变量来代替OP表和视图。

FOR

数据透视表之前的数据如下:

-- template13_ticker_data (with sector_char added)
DECLARE @tickerData Table
(
    sector INT,
    ticker CHAR(4),
    m_ticker CHAR(4),
    sector_char char(10)
)
-- template13_vw
DECLARE @Company Table
(
    m_ticker CHAR(4),
    ticker CHAR(4),
    company_name VARCHAR(100)
)

INSERT INTO @tickerData (sector, ticker)
VALUES (5 ,'ADNT')
,(5 ,'AUTO')
,(5 ,'THRM')
,(5 ,'ALSN')
,(5 ,'ALV')
,(12,'HES')
,(12,'AM')
,(12,'PHX')
,(12,'NBR')
,(12,'AMRC')


INSERT INTO @Company (ticker, company_name)
VALUES ('ADNT','Adient PLC')
,('AUTO','Autobytel Inc.')
,('THRM','Gentherm Inc')
,('ALSN','Allison Transmission Holdings, Inc.')
,('ALV ','Autoliv, Inc.')
,('HES ','Hess Corporation')
,('AM  ','Antero Midstrm')
,('PHX ','Panhandle Royalty Company')
,('NBR ','Nabors Industries Ltd.')
,('AMRC','Ameresco, Inc.')

-- Just re-creating a record set that matches the given data and query structure
UPDATE @tickerData SET m_ticker = ticker
UPDATE @Company SET m_ticker = ticker
-- populate 'sector_char' to show multiple aggregates
UPDATE @tickerData SET sector_char = '|' + cast(sector as varchar) + '|'

-- Unpivoted data Proof
SELECT d.sector, d.sector_char, d.ticker, v.company_name, ROW_NUMBER() OVER(PARTITION BY d.sector ORDER BY d.sector) rn
FROM @tickerData d, @Company v
WHERE d.m_ticker = v.m_ticker

现在可视化您期望的结果子集,以显示我创建的sector sector_char ticker company_name rn ------------------------------------------------------------------------ 5 |5| ADNT Adient PLC 1 5 |5| AUTO Autobytel Inc. 2 5 |5| THRM Gentherm Inc 3 5 |5| ALSN Allison Transmission Holdings, Inc. 4 5 |5| ALV Autoliv, Inc. 5 12 |12| HES Hess Corporation 1 12 |12| AM Antero Midstrm 2 12 |12| PHX Panhandle Royalty Company 3 12 |12| NBR Nabors Industries Ltd. 4 12 |12| AMRC Ameresco, Inc. 5 包含在最终输出中的多列操作的局限性

sector_char

因为我们要从原始行输出中获得多于一列的输出(每行中的sector sector_char ticker_1 company_1 ticker_2 company_2 ----------------------------------------------------------------------------- 5 |5| ADNT Adient PLC AUTO Autobytel Inc. 12 |12| HES Hess Corporation AM Antero Midstrm ticker),所以我们必须使用以下技术之一:

  1. 将多个列中的值连接到一个列中
    • 仅当您可以在需要使用各个值之前轻松拆分这些列时有用,或者如果您不需要处理这些列,则仅用于可视化。
  2. 执行多个company查询并加入结果
    • 当每一列的聚合逻辑不同时,或者不是简单地将行值转换为列值(将多行聚合到单个单元格响应中)时,这是必需的。
    • 在这种情况下,当我们只是转换值时(例如,聚合的结果将与原始单元格值匹配),我认为这有点像 hack ,但也可以语法比其他语法少。
        

      我说 hack 是因为核心PIVOT逻辑是重复的,这使得查询的发展变得更加困难。

  3. 在唯一列上执行单个PIVOT,在其他表上联接以构建其他列
    • 这很容易在输出中允许无限数量的附加行。 PIVOT解析包含要在最终结果中显示的多个值的表的ID。

让我们首先看3,因为这演示了一个PIVOT,以及如何为每个PIVOT结果包括多列:

  

在此示例中,每个扇区最多允许8个结果,请务必注意,您必须指定PIVOT中的所有输出列,它不是动态的。

     
    

您可以使用动态查询来测试所需的最大列数,并根据这些结果生成以下查询。

  

还要注意,在此解决方案中,我们不需要在PIVOT源查询中的template13_vw表上进行联接,而是对结果进行了联接,这就是枢轴返回{ {1}}(我认为是关键),而不是最终结果中显示的PIVOT

m_ticker

以下是同一查询,使用多个ticker查询将它们连接在一起。 请注意,在这种情况下,两个-- NOTE: using CTE here, you could use table variables, temporary tables or whatever else you need ;WITH TickersBySector as ( -- You must specify the fixed number of columns in the output SELECT sector, sector_char, [1] as [m_ticker_1],[2] as [m_ticker_2],[3] as [m_ticker_3],[4] as [m_ticker_4],[5] as [m_ticker_5],[6] as [m_ticker_6],[7] as [m_ticker_7],[8] as [m_ticker_8] FROM ( SELECT d.sector, d.sector_char, d.m_ticker, ROW_NUMBER() OVER(PARTITION BY d.sector ORDER BY d.sector) rn FROM template13_ticker_data d /* OPs Syntax */ -- FROM @tickerData d /* Use this with the proof table variables */ ) data PIVOT ( MAX(m_ticker) FOR rn IN ( [1],[2],[3],[4],[5],[6],[7],[8]) ) as PivotTable ) -- To use with the proof table variables, replace 'template13_vw' with '@Company' SELECT sector, sector_char ,c1.[ticker] as [ticker_1], c1.company_name as [company_1] ,c2.[ticker] as [ticker_2], c2.company_name as [company_2] ,c3.[ticker] as [ticker_3], c3.company_name as [company_3] ,c4.[ticker] as [ticker_4], c4.company_name as [company_4] ,c5.[ticker] as [ticker_5], c5.company_name as [company_5] ,c6.[ticker] as [ticker_6], c6.company_name as [company_6] ,c7.[ticker] as [ticker_7], c7.company_name as [company_7] ,c8.[ticker] as [ticker_8], c8.company_name as [company_8] FROM TickersBySector LEFT OUTER JOIN template13_vw c1 ON c1.m_ticker = TickersBySector.m_ticker_1 LEFT OUTER JOIN template13_vw c2 ON c2.m_ticker = TickersBySector.m_ticker_2 LEFT OUTER JOIN template13_vw c3 ON c3.m_ticker = TickersBySector.m_ticker_3 LEFT OUTER JOIN template13_vw c4 ON c4.m_ticker = TickersBySector.m_ticker_4 LEFT OUTER JOIN template13_vw c5 ON c5.m_ticker = TickersBySector.m_ticker_5 LEFT OUTER JOIN template13_vw c6 ON c6.m_ticker = TickersBySector.m_ticker_6 LEFT OUTER JOIN template13_vw c7 ON c7.m_ticker = TickersBySector.m_ticker_7 LEFT OUTER JOIN template13_vw c8 ON c8.m_ticker = TickersBySector.m_ticker_8 都带回附加的公共列PIVOT并不重要,因此当汇总或附加的公共列可能因不同的结果而不同时,请使用这种语法样式设置。

PIVOT