【问题标题】:Splitting data into a per-year basis using SQL with pivots使用带数据透视的 SQL 将数据拆分为每年
【发布时间】:2011-11-25 03:43:18
【问题描述】:

我在弄清楚如何构建一系列 SQL 语句以将我拥有的一些数据拆分为每年的数据时遇到了一些麻烦。在这么多年中,有 n 个项目在一组天的记录数量。这是我拥有的主要数据的一个小示例布局。

   |========|==============|===========|
   | Name   | Date         | Quantity  |
   |========|==============|===========|
 1 | AAAAA  | 10-DEC-2008  | 5         |
 2 | AAAAA  | 11-DEC-2008  | 2         |
 3 | AAAAA  | 12-DEC-2008  | 0         |
 4 | AAAAA  | 09-DEC-2009  | 3         |
 5 | AAAAA  | 10-DEC-2009  | 2         |
 6 | AAAAA  | 11-DEC-2009  | 3         |
 7 | BBBBB  | 10-DEC-2008  | 5         |
 8 | BBBBB  | 11-DEC-2008  | 2         |
 9 | BBBBB  | 12-DEC-2008  | 0         |
10 | BBBBB  | 09-DEC-2009  | 3         |
11 | BBBBB  | 10-DEC-2009  | 1         |
12 | BBBBB  | 11-DEC-2009  | 0         |
   |========|==============|===========|

我需要把它转换成一个表格。

   |========|==============|===============|===============|
   | Name   | Date         | Quantity 2008 | Quantity 2009 |
   |========|==============|===============|===============|
 1 | AAAAA  | 09-DEC       |               | 3             |
 2 | AAAAA  | 10-DEC       | 5             | 2             |
 3 | AAAAA  | 11-DEC       | 2             | 3             |
 4 | AAAAA  | 12-DEC       | 0             |               |
 5 | BBBBB  | 09-DEC       |               | 3             |
 6 | BBBBB  | 10-DEC       | 5             | 1             |
 7 | BBBBB  | 11-DEC       | 2             | 0             |
 8 | BBBBB  | 12-DEC       | 0             |               |
   |========|==============|===============|===============|

应该假设数据库中有数千个命名项目,并且每年记录的开始日期会有所不同,例如,2010 年 12 月 6 日和 2009 年 12 月 5 日。

希望有人能提供帮助。

【问题讨论】:

  • 无论何时要将列转换为行或反之亦然,请查看 pivot/unpivot(在 11g 上显式,或在早期版本中模拟显式函数的“技术”)。

标签: sql database oracle pivot


【解决方案1】:

如果您使用的是 Oracle 11g,您可以将表格旋转为:

select *
  from (    
    select name,
           to_char(theDate, 'DD-MON') as dayMonth,
           extract(year from thedate) as year,
           quantity
      from yourTable
) 
 pivot (sum(quantity) as quantity for (year) in (2008 as y2008, 2009 as y2009))
order by name, dayMonth;

返回以下内容

NAME  DAYMONTH        Y2008_QUANTITY         Y2009_QUANTITY         
----- --------------- ---------------------- ---------------------- 
AAAAA 09-DEC                                 3                      
AAAAA 10-DEC          5                      2                      
AAAAA 11-DEC          2                      3                      
AAAAA 12-DEC          0                                        
BBBBB 09-DEC                                 3                      
BBBBB 10-DEC          5                      1                      
BBBBB 11-DEC          2                      0                      
BBBBB 12-DEC          0                                           

8 rows selected

【讨论】:

  • 很好的答案,谢谢。这是我最终采用的方法,使用枢轴。
  • @LewisNorton 如果这是最佳答案,您仍然可以根据需要将其标记为最佳答案。
【解决方案2】:

在 Oracle11 之前,您可以使用这个标准的数据透视技巧:

SQL> create table mytable (name,mydate,quantity)
  2  as
  3  select 'AAAAA', date '2008-12-10', 5 from dual union all
  4  select 'AAAAA', date '2008-12-11', 2 from dual union all
  5  select 'AAAAA', date '2008-12-12', 0 from dual union all
  6  select 'AAAAA', date '2009-12-09', 3 from dual union all
  7  select 'AAAAA', date '2009-12-10', 2 from dual union all
  8  select 'AAAAA', date '2009-12-11', 3 from dual union all
  9  select 'BBBBB', date '2008-12-10', 5 from dual union all
 10  select 'BBBBB', date '2008-12-11', 2 from dual union all
 11  select 'BBBBB', date '2008-12-12', 0 from dual union all
 12  select 'BBBBB', date '2009-12-09', 3 from dual union all
 13  select 'BBBBB', date '2009-12-10', 1 from dual union all
 14  select 'BBBBB', date '2009-12-11', 0 from dual
 15  /

Table created.

SQL> select name
  2       , to_char(mydate,'dd-MON')
  3       , sum(case extract(year from mydate) when 2008 then quantity end) quantity_2008
  4       , sum(case extract(year from mydate) when 2009 then quantity end) quantity_2009
  5    from mytable
  6   group by name
  7       , to_char(mydate,'dd-MON')
  8   order by name
  9       , to_char(mydate,'dd-MON')
 10  /

NAME  TO_CHA QUANTITY_2008 QUANTITY_2009
----- ------ ------------- -------------
AAAAA 09-DEC                           3
AAAAA 10-DEC             5             2
AAAAA 11-DEC             2             3
AAAAA 12-DEC             0
BBBBB 09-DEC                           3
BBBBB 10-DEC             5             1
BBBBB 11-DEC             2             0
BBBBB 12-DEC             0

8 rows selected.

问候,
抢。

【讨论】:

    【解决方案3】:

    这样的事情应该可以完成:

    SELECT
        Name, FormattedDate, SUM(Quantity_2008), SUM(Quantity_2009)
    FROM
    (
    SELECT
        Name,
        ConvertDateToDayMonthRepresentation(YourDate) as FormattedDate,
        DECODE(EXTRACT(YEAR FROM YourDate), 2008, Quantity, 0) as Quantity_2008, 
        DECODE(EXTRACT(YEAR FROM YourDate), 2009, Quantity, 0) as Quantity_2009
    FROM
        YourTable
    )
    GROUP BY Name, FormattedDate;
    

    请注意:

    1. 您需要为想要拥有的每一年添加代码 - 您的查询不能有动态列。
    2. ConvertDateToDayMonthRepresentation 是一个用户定义的函数,它应该将日期转换为没有年份的日期和月份的字符串表示形式。使用EXTRACT 创建很简单。

    【讨论】:

    • 丹尼尔,正在努力解决您的问题。 decode/pivot 方法似乎是要走的路。会尽快回复您。
    • 这种解码方法是行之有效的。感谢您的快速回答。
    • @RobvanWijk:我的回答只有一个问题:我使用了 OP 提供的列名。除此之外,它是完全有效的。我纠正了这个错误 - 请删除您的反对票。
    • 很抱歉你有这种感觉。我的反对意见是因为您的答案未经测试就没有这样说。我应该从一开始就告诉你。对此感到抱歉。当我否决它时,答案包含一个关键字作为列名。我还认为您缺少聚合函数,但由于答案已被编辑,我可能在那个问题上错了。无论如何,这不值得这么大惊小怪,所以我删除了反对票:-)
    • @RobvanWijk:感谢您删除反对票。在投票时,最好将问题准确地告诉回答者。这样误会很容易解决。答案是否正确不需要测试。我使用保留关键字阻止了代码的成功执行,这是正确的。但是,它并没有改变答案的价值,因为 OP 询问了一个完全不同的问题,并意识到 date 是一个错误的列名。缺少聚合函数从来都不是问题,它们从一开始就存在,(续)
    猜你喜欢
    • 1970-01-01
    • 2022-12-14
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    相关资源
    最近更新 更多