如何将数据透视表应用于查询结果

How to apply pivot to result of query

这是我当前的查询:

SELECT Name, Code, Today
    , Account || Currency as Accounts
FROM (
    SELECT
          b.description AS Name
        , b.contragentidentifycode AS Code
        , c.systemday AS Today
        , b.accountno AS Account
        , b.currencysname AS Currency
    FROM vAACCOUNT b, currentdaysetting c
    WHERE b.contragentid = 412
    AND b.accountno LIKE '26%' 
)

它给了我这样的结果:

Name  | Code  | Today      | Accounts
---------------------------------------
name1 | code1 | 07.09.2016 | acc1+curr1
name1 | code1 | 07.09.2016 | acc2+curr1
name1 | code1 | 07.09.2016 | acc1+curr2       
name1 | code1 | 07.09.2016 | acc2+curr2       
name1 | code1 | 07.09.2016 | acc1+curr3            
name1 | code1 | 07.09.2016 | acc2+curr3            
name1 | code1 | 07.09.2016 | acc1+curr4
name1 | code1 | 07.09.2016 | acc2+curr4

我需要将此视图转换为:

Name  | Code  | Today      | someName1  |  someName2  |  someName3  |  someName4  |  someName5  |  someName6  |  someName7  |  someName8
-------------------------------------------------------------------------------------------------------------------------------------------
name1 | code1 | 07.09.2016 | acc1+curr1 | acc2+curr1  | acc1+curr2  | acc2+curr2  | acc1+curr3  | acc2+curr3  | acc1+curr4  | acc2+curr4

我想我很可能为此必须使用关键字 "Pivot"。但是我所有的尝试都失败了。我无法将我在示例中看到的内容投射到我的 table。请帮忙。

对于列数,我可以添加这样的 "id" 列:

SELECT id, Name, Code, Today
    , Account || Currency as Accounts
FROM (
    SELECT
         row_number() over (ORDER BY b.id) AS id
        , b.description AS Name
        ...

在我的场景中:

如果您知道所有账户+货币组合,您可以使用这个数据透视表(我在这里只实现了其中的 3 个):

select *
from (
    <your-query>    )
pivot  (
    min(accounts) as accounts FOR (accounts) in ('acc1+curr1' as a, 'acc2+curr1' as b, 'acc1+curr2' c)
    );

根据我上面的评论,我认为 PIVOT 不适合你。 @RoundFour 的答案有效,但需要您知道并编码 Account || 的所有可能值货币。这表明这些项目永远不会有新的价值 - 我发现这不太可能。

以下将允许您切换数据的形状。它没有对数据中的 做出任何假设,但它确实对可能的组合数量进行了假设 - 我已经编码为八个。

WITH account_data (name,code,today,account) 
AS
 (
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr1' FROM dual UNION ALL
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr1' FROM dual UNION ALL
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr2' FROM dual UNION ALL     
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr2' FROM dual UNION ALL       
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr3' FROM dual UNION ALL            
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr3' FROM dual UNION ALL            
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr4' FROM dual UNION ALL
 SELECT 'name1','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr4' FROM dual UNION ALL
 SELECT 'name2','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr1' FROM dual UNION ALL
 SELECT 'name2','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr1' FROM dual UNION ALL
 SELECT 'name2','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc1+curr2' FROM dual UNION ALL     
 SELECT 'name3','code1',TO_DATE('07.09.2016','DD.MM.YYYY'),'acc2+curr2' FROM dual 
 )
SELECT
 name
,code
,today
,MAX(account1)
,MAX(account2)
,MAX(account3)
,MAX(account4)
,MAX(account5)
,MAX(account6)
,MAX(account7)
,MAX(account8)
FROM
 (SELECT 
   name
  ,code
  ,today
  ,CASE
    WHEN rn = 1 THEN account
   END                             account1
  ,CASE
    WHEN rn = 2 THEN account
   END                             account2
  ,CASE
    WHEN rn = 3 THEN account
   END                             account3
  ,CASE
    WHEN rn = 4 THEN account
   END                             account4
  ,CASE
    WHEN rn = 5 THEN account
   END                             account5
  ,CASE
    WHEN rn = 6 THEN account
   END                             account6
  ,CASE
    WHEN rn = 7 THEN account
   END                             account7
  ,CASE
    WHEN rn = 8 THEN account
   END                             account8
  FROM
   (SELECT
    name 
   ,code
   ,today
   ,account
   ,ROW_NUMBER() OVER (PARTITION BY name ORDER BY account)   rn
   FROM
    account_data
   )
  )
GROUP BY
 name
,code
,today
;

UPDATE >>>>>>>>>

上面的 WITH... 子句只是因为我的系统中没有您的表和数据。我已经使用您的查询作为指南重写了我的答案 - 请注意我无法测试这个 ...

SELECT
 name
,code
,today
,MAX(account1)
,MAX(account2)
,MAX(account3)
,MAX(account4)
,MAX(account5)
,MAX(account6)
,MAX(account7)
,MAX(account8)
FROM
 (SELECT 
   name
  ,code
  ,today
  ,CASE
    WHEN rn = 1 THEN account
   END                             account1
  ,CASE
    WHEN rn = 2 THEN account
   END                             account2
  ,CASE
    WHEN rn = 3 THEN account
   END                             account3
  ,CASE
    WHEN rn = 4 THEN account
   END                             account4
  ,CASE
    WHEN rn = 5 THEN account
   END                             account5
  ,CASE
    WHEN rn = 6 THEN account
   END                             account6
  ,CASE
    WHEN rn = 7 THEN account
   END                             account7
  ,CASE
    WHEN rn = 8 THEN account
   END                             account8
  FROM
   (SELECT
     b.description AS Name
    ,b.contragentidentifycode AS Code
    ,c.systemday AS Today
    ,b.accountno AS Account
    ,b.currencysname AS Currency
    ,b.accountno || b.currencysname AS Accounts
    ,ROW_NUMBER() OVER (PARTITION BY b.description ORDER BY b.accountno)   rn
    FROM vAACCOUNT b, currentdaysetting c
    WHERE b.contragentid = 412
    AND b.accountno LIKE '26%' 
   )
  )
GROUP BY
 name
,code
,today
;

这是我的关键解决方案:

SELECT *
FROM (
    SELECT id, Name, Code, Today, Account || Currency as Accounts
    FROM (
        SELECT
              row_number() over (ORDER BY b.id) AS id
            , b.description AS Name
            , b.contragentidentifycode AS Code
            , c.systemday AS Today
            , b.accountno AS Account
            , b.currencysname AS Currency
        FROM vAACCOUNT b, currentdaysetting c
        WHERE b.contragentid = 412
        AND b.accountno LIKE '26%' 
    )
)
pivot (
    MIN(Accounts)
    FOR ID  IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
) pvt