Поворот нескольких строк / столбцов в 1 ряд - PullRequest
1 голос
/ 20 июня 2019

Нам нужно взять несколько строк и несколько столбцов и транспонировать их в 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.

Нам нужен 1 ряд на каждый идентификатор, с каждым TICKER / COMPANY в отдельном столбце.Таким образом, вывод будет выглядеть следующим образом:

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

Вы получите идею. 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 голосов
/ 20 июня 2019

Первое, что нужно понять о сводках: вы выбираете один столбец в наборе результатов, который будет действовать как якорь PIVOT, шарнир, вокруг которого будут вращаться данные, это указано в предложении FOR.

Вы можете только PIVOT FOR один столбец, но вы можете создать этот столбец в подзапросе или из объединений или представлений в качестве целевого запроса данных, OP имеетиспользуется ROW_NUMBER(), но вы можете использовать любой механизм SQL, какой пожелаете, даже оператор CASE, чтобы создать пользовательский столбец для поворота, если в наборе данных нет естественного столбца для использования.

PIVOT создаст столбец для каждого значения в столбце FOR и даст этому столбцу значение функции агрегирования, которую выуказать

Это помогает визуализировать построенный набор записей, прежде чем применять сводную диаграмму, следующий SQL может воссоздать сценарий данных, представленный OP.Я использовал здесь переменные таблиц вместо таблиц и представлений OP.

-- 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

Поскольку мы хотим, чтобы более 1 столбца выводилось из исходного вывода строки, (tickerи company из каждой строки) мы должны использовать один из следующих методов:

  1. Объединить значения из нескольких столбцов в один столбец
    • Полезно, только если вы можете легко разбитьэти столбцы, прежде чем вам нужно использовать отдельные значения, или если вам не нужно обрабатывать столбцы, это просто для визуализации.
  2. выполнить несколько запросов PIVOT и присоединиться крезультаты
    • Необходимы, когда логика агрегирования различна для каждого столбца или вы не просто переносите значение строки в значение столбца (агрегированиеng несколько строк в ответе одной ячейки.)
    • В подобных сценариях, когда мы просто переносим значение (например, результат агрегата будет соответствовать исходному значению ячейки), я считаю это немного hack , но также может иметь меньший синтаксис, чем альтернативный.

      Я говорю hack , потому что базовая логика PIVOT дублируется, что усложняет обслуживание по мере развития запроса.

  3. выполнить один PIVOT для уникального столбца, объединиться с другими таблицами, чтобы создать дополнительные столбцы
    • Это легко допускает неограниченное количество дополнительных строк в выводе.PIVOT разрешает идентификатор таблицы, которая содержит несколько значений, которые мы хотим отобразить в окончательных результатах.

Давайте сначала посмотрим на 3, так как это демонстрируетодин PIVOT и как включить несколько столбцов для каждого из результатов PIVOT:

В этом примере я допустил до 8 результатов для каждого сектора, важно отметить, что вы ДОЛЖНЫ укажите все выходные столбцы из PIVOT, он не является динамическим.

Вы можете использовать динамические запросы для проверки максимального количества нужных вам столбцов и сгенерировать следующий запрос на основе этих результатов.

Также обратите внимание, чтов этом решении нам не нужно присоединяться к таблице template13_vw в исходном запросе 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 возвращали дополнительный общий столбец sector_char, поэтому используйте этот стиль синтаксиса, когда агрегат или дополнительный общий столбец могут отличаться для разных наборов результатов.

;WITH TickersBySector as
(
    -- You must specify the fixed number of columns in the output
    SELECT sector, sector_char, [1] as [ticker_1],[2] as [ticker_2],[3] as [ticker_3],[4] as [ticker_4],[5] as [ticker_5],[6] as [ticker_6],[7] as [ticker_7],[8] as [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
)
, CompanyBySector as
(
    -- You must specify the fixed number of columns in the output
    SELECT sector,[1] as [company_1],[2] as [company_2],[3] as [company_3],[4] as [company_4],[5] as [company_5],[6] as [company_6],[7] as [company_7],[8] as [company_8]
    FROM (
        SELECT d.sector, v.company_name, 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 */
        INNER JOIN template13_vw v /* OPs Syntax */
        -- INNER JOIN @Company v /* Use this with the proof table variables */
            ON d.m_ticker = v.m_ticker
        ) data
    PIVOT (
      MAX(company_name)
      FOR rn IN ( [1],[2],[3],[4],[5],[6],[7],[8])
    ) as PivotTable
)
SELECT TickersBySector.sector, sector_char
    ,[ticker_1], [company_1] 
    ,[ticker_2], [company_2] 
    ,[ticker_3], [company_3] 
    ,[ticker_4], [company_4] 
    ,[ticker_5], [company_5] 
    ,[ticker_6], [company_6] 
    ,[ticker_7], [company_7] 
    ,[ticker_8], [company_8]
FROM TickersBySector
INNER JOIN CompanyBySector ON TickersBySector.sector = CompanyBySector.sector
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...