【问题标题】:Pivot every n number of records每 n 条记录旋转一次
【发布时间】:2014-08-06 09:38:16
【问题描述】:

我有一张这样的桌子:

+----------------------------------------------------+
| PI  | VS  | S | HID | DESC          | MS   | QT    |
+----------------------------------------------------+
| 195 | 152 | 0 | 554 | Description 1 | 2013 |       |
| 195 | 152 | 0 | 554 | Description 1 | JAN  | 3677  |
| 195 | 152 | 0 | 554 | Description 1 | FEB  | 4187  |
| 195 | 152 | 0 | 554 | Description 1 | MAR  | 3344  |
| 195 | 152 | 0 | 554 | Description 1 | APR  | 4001  |
| 195 | 152 | 0 | 554 | Description 1 | MAY  | 4966  |
| 195 | 152 | 0 | 554 | Description 1 | JUN  | 1079  |
| 195 | 152 | 0 | 554 | Description 1 | JUL  | 452   |
| 195 | 152 | 0 | 554 | Description 1 | AUG  | 2224  |
| 195 | 152 | 0 | 554 | Description 1 | SEP  | 45478 |
| 195 | 152 | 0 | 554 | Description 1 | OCT  | 2104  |
| 195 | 152 | 0 | 554 | Description 1 | NOV  | 122   |
| 195 | 152 | 0 | 554 | Description 1 | DEC  | 110   |
+----------------------------------------------------+
| 195 | 152 | 0 | 554 | Description 1 | 2013 |       |
| 195 | 152 | 0 | 554 | Description 1 | JAN  | 3377  |
| 195 | 152 | 0 | 554 | Description 1 | FEB  | 4187  |
| 195 | 152 | 0 | 554 | Description 1 | MAR  | 3344  |
| 195 | 152 | 0 | 554 | Description 1 | APR  | 4001  |
| 195 | 152 | 0 | 554 | Description 1 | MAY  | 4966  |
| 195 | 152 | 0 | 554 | Description 1 | JUN  | 1076  |
| 195 | 152 | 0 | 554 | Description 1 | JUL  | 452   |
| 195 | 152 | 0 | 554 | Description 1 | AUG  | 2224  |
| 195 | 152 | 0 | 554 | Description 1 | SEP  | 45478 |
| 195 | 152 | 0 | 554 | Description 1 | OCT  | 21554 |
| 195 | 152 | 0 | 554 | Description 1 | NOV  | 122   |
| 195 | 152 | 0 | 554 | Description 1 | DEC  | 110   |
+----------------------------------------------------+

我想提取第一行,然后将接下来的 12 行连接为字段,使用它们的内容作为列名。

类似:

+--------------------------------------------------------------------------------------------------------------------------------+
| PI  | VS  | S | HID | DESC           | YEAR | JAN  | FEB  | MAR  | APR  | MAY  | JUN  | JUL | AUG  |  SEP  | OCT   | NOV | DEC |
+--------------------------------------------------------------------------------------------------------------------------------+
| 195 | 152 | 0 | 554 | Description 1  | 2013 | 3677 | 4187 | 3344 | 4001 | 4966 | 1079 | 452 | 2224 | 45478 | 2104  | 122 | 110 |
+--------------------------------------------------------------------------------------------------------------------------------+
| 195 | 152 | 0 | 554 | Description 1  | 2013 | 3377 | 4187 | 3344 | 4001 | 4966 | 1076 | 452 | 2224 | 45478 | 21554 | 122 | 110 |
+--------------------------------------------------------------------------------------------------------------------------------+

这样的事情可能吗?

我读过数据透视表,这似乎与我想做的类似,但我没有找到任何类似的示例。

我该怎么做?


我尝试了什么:

WITH pivot_data AS (
  SELECT PI, VS, S, HID, DESC, MS, QT VOLUME
  FROM MONTHLY_RATES
)
SELECT *
FROM pivot_data
PIVOT (
  sum(VOLUME)
  FOR MS
  IN  (
    'JAN',
    'FEB',
    'MAR',
    'APR',
    'MAY',
    'JUN',
    'JUL',
    'AUG',
    'SEP',
    'OCT',
    'NOV',
    'DEC'
  )
);

它有效但确实省略了年份(我需要保留),并且它总结每个月的值以防重复值,这不是我想要什么。

更新

MONTHLY_RATES表:

CREATE TABLE MONTHLY_RATES (
  PI   VARCHAR2(3 CHAR), 
  VS   VARCHAR2(3 CHAR),  
  S    VARCHAR2(2 CHAR),  
  HID  VARCHAR2(3 CHAR),  
  "DESC" VARCHAR2(200 CHAR),  
  MS   VARCHAR2(4 CHAR),  
  QT   NUMBER(10,0)
);

INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', '2013', null);
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JAN', '3677');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'FEB', '4187');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'MAR', '3344');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'APR', '4001');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'MAY', '4966');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JUN', '1079');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JUL', '452');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'AUG', '2224');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'SEP', '45478');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'OCT', '2104');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'NOV', '122');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'DEC', '110');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', '2013', null);
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JAN', '3377');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'FEB', '4187');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'MAR', '3344');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'APR', '4001');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'MAY', '4966');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JUN', '1076');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'JUL', '452');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'AUG', '2224');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'SEP', '45478');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'OCT', '21554');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'NOV', '122');
INSERT INTO MONTHLY_RATES VALUES('195', '152', '0', '554', 'Description 1', 'DEC', '110');

【问题讨论】:

  • 你真的有两个相同的结果集一个一个吗?您打算使用 2013 年和 2014 年而不是 2013 年和 2013 年吗?
  • @zaratustra 不幸的是我不知道。该表不是由我填写的,我只是想要一个更“可读”的表,我唯一知道的是我将有 13 行的“包”,第一行包含年份,其他 12 行包含月份。事实上是的,我可以在同一年有 30 次(所以 30*13 总记录,同一年)不同月份的值......
  • 请给我们提供脚本或 CTE?
  • 我们应该如何区分这两组记录?
  • 但是如何确定相关的十三条记录呢?表中没有固有的顺序;即使您同时插入 13 个,也不能保证它们会被连续存储或检索。您必须拥有每个“集合”成员共有的东西,并且该“集合”是唯一的。

标签: sql oracle plsql pivot-table


【解决方案1】:

看看这个:

with t as (
    SELECT PI, MS,VS,S,HID,"DESC", qt
         , case when qt is null and REGEXP_LIKE(ms, '^20') then to_number(ms, '9999') end yr, rownum rn
      FROM MONTHLY_RATES
), t1 as (
    SELECT PI, MS,VS,S,HID,"DESC", qt
         , case when yr is not null then yr 
                    else lag(yr, mod(rn - 1,13)) over(order by rn) 
               end yr
             , 'G' || trunc((rn-1)/13)  grp
      FROM t
)
select distinct f.* from
(SELECT *
  FROM t1
 PIVOT (
        max(qt)
        FOR MS IN  ('JAN','FEB','MAR','APR','MAY ','JUN ','JUL ','AUG ','SEP ','OCT ','NOV ','DEC ')
       ))f

PI  VS  S  HID DESC                    YR GRP      'JAN'      'FEB'      'MAR'      'APR'
--- --- -- --- --------------- ---------- --- ---------- ---------- ---------- ----------
195 152 0  554 Description 1         2013 G1        3377       4187       3344       4001
195 152 0  554 Description 1         2014 G2        3377       4187       3344       4001
195 152 0  554 Description 1         2013 G0        3677       4187       3344       4001

我减少了结果输出,所以没有一堆月份。

SQLFiddle

【讨论】:

    【解决方案2】:

    检查这是否对您有帮助:

    在此处更新最终小提琴并处理年份条件http://sqlfiddle.com/#!4/e3047/2

    WITH pivot_data AS
    (
      SELECT MTEMP1.*, MTEMP2.YEARR FROM
     ( SELECT M1.*, 'G' || TRUNC((ROWNUM-1)/13) AS GROUP_ID FROM 
     MYTABLE M1
     ) MTEMP1
     JOIN
      ( SELECT M2.MS YEARR, 'G' || (ROWNUM-1) AS GROUP_ID FROM MYTABLE M2 WHERE REGEXP_LIKE (M2.MS,'^20') 
    
       ) MTEMP2
     ON MTEMP1.GROUP_ID = MTEMP2.GROUP_ID
    
    )
    
    SELECT *
    FROM pivot_data
    PIVOT (
      sum(QT)
      FOR MS
      IN  (     'JAN',        'FEB',        'MAR',        'APR',        'MAY',
                'JUN',        'JUL',        'AUG',        'SEP',        'OCT',
                'NOV',        'DEC'
          )
    );
    

    WITH pivot_data AS
    
    (SELECT M1.*, 'G' || TRUNC((ROWNUM-1)/13) AS GROUP_ID FROM MYTABLE M1)
    
    SELECT *
    FROM pivot_data
    PIVOT (
      sum(QT)
      FOR MS
      IN  (     'JAN',        'FEB',        'MAR',        'APR',        'MAY',
                'JUN',        'JUL',        'AUG',        'SEP',        'OCT',
                'NOV',        'DEC'
          )
    );
    

    这里的原始小提琴:http://sqlfiddle.com/#!4/46263/8 在此处更新 FIDDLE 以处理超过 26 条记录*http://sqlfiddle.com/#!4/6ecc9/12*

    由于您没有可以对记录进行分组的列,但您确定每个记录只有 13 条记录,因此我正在创建一个临时字段调用 GROUP_ID,它将每组记录分类为不同的组。当您为组应用数据透视时,您会得到您想要的结果。

    【讨论】:

    • 这是错误的。查看当超过 26 行时您的查询会做什么:sqlfiddle.com/#!4/6ecc9/2(注意 G2 和 G3 上的 Jan 值)。而且您没有根据请求返回 YEAR 列。
    • 实际上我在发表评论时忘记投反对票,但老实说,我现在很想这样做,因为您的查询仍然没有返回 YEAR 和 3 个赞成票的一半- 解决方案似乎太多了。您认为您可以再次查看您的答案吗?
    • @NishanthiGrashia 很好,我想这个解决方案比我提供的要好,你需要任何不使用的分析函数,这很容易理解。
    • 反对票来自我。原因是(使用ROWNUM)您假设行将始终以相同的顺序返回,并且该顺序将与 OP 的示例中的相同。这不能保证。所以答案是错误的(基于问题的错误假设但仍然是错误的。)检查这个Fiddle
    • @NishanthiGrashia - 但“按指定顺序”并不意味着什么。没有顺序。我只能猜测 OP 是根据插入记录的方式/时间来假设固有顺序,但这将是一个错误且不安全的前提。使用rownum也是基于同样的前提。正如 ypercube 所说,这是问题的错,数据模型被破坏了;但使用 rownum 并不能解决问题。
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    相关资源
    最近更新 更多