如何在Sql中创建“月”列?

时间:2010-02-19 13:40:53

标签: sql-server

我有一组看起来像这样的数据(非常简化):

productId    Qty   dateOrdered
---------    ---   -----------
       1       2    10/10/2008
       1       1    11/10/2008
       1       2    10/10/2009
       2       3    10/12/2009
       1       1    10/15/2009
       2       2    11/15/2009

除此之外,我们正在尝试创建一个查询来获取类似的内容:

productId  Year  Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
---------  ----  --- --- --- --- --- --- --- --- --- --- --- ---
        1  2008    0   0   0   0   0   0   0   0   0   2   1   0
        1  2009    0   0   0   0   0   0   0   0   0   3   0   0
        2  2009    0   0   0   0   0   0   0   0   0   3   2   0

我现在这样做的方式,我正在做12次选择,每个月一次,并把它们放在临时表中。然后我做了一个巨大的加入。一切正常,但这家伙很慢。

我知道这并不多,但我知道我几乎没有资格成为db世界中的tyro,我想知道是否有一个更好的高级方法,我可能会尝试。 (我猜是有的。)

(我正在使用MS Sql Server,因此特定于该数据库的答案很好。)

(我刚刚开始将“PIVOT”视为可能的帮助,但我对此一无所知,所以如果有人想对此发表评论,那也可能会有所帮助。)

6 个答案:

答案 0 :(得分:10)

select productId, Year(dateOrdered) Year
  ,isnull(sum(case when month(dateOrdered) = 1 then Qty end), 0) Jan
  ,isnull(sum(case when month(dateOrdered) = 2 then Qty end), 0) Feb 
  ,isnull(sum(case when month(dateOrdered) = 3 then Qty end), 0) Mar
  ,isnull(sum(case when month(dateOrdered) = 4 then Qty end), 0) Apr
  ,isnull(sum(case when month(dateOrdered) = 5 then Qty end), 0) May
  ,isnull(sum(case when month(dateOrdered) = 6 then Qty end), 0) Jun
  ,isnull(sum(case when month(dateOrdered) = 7 then Qty end), 0) Jul
  ,isnull(sum(case when month(dateOrdered) = 8 then Qty end), 0) Aug
  ,isnull(sum(case when month(dateOrdered) = 9 then Qty end), 0) Sep
  ,isnull(sum(case when month(dateOrdered) = 10 then Qty end), 0) Oct
  ,isnull(sum(case when month(dateOrdered) = 11 then Qty end), 0) Nov
  ,isnull(sum(case when month(dateOrdered) = 12 then Qty end), 0) Dec
from Table1
group by productId, Year(dateOrdered)

SQL Fiddle

答案 1 :(得分:1)

SELECT productId, YEAR,
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=1),0) as 'JAN',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=2),0) as 'FEB',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=3),0) as 'MAR',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=4),0) as 'APR',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=5),0) as 'MAY',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=6),0) as 'JUN',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=7),0) as 'JUL',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=8),0) as 'AUG',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=9),0) as 'SEP',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=10),0) as 'OCT',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=11),0) as 'NOV',
ISNULL((SELECT SUM(Qty) FROM Product WHERE productId=X.productId AND YEAR=YEAR(dateOrdered) AND MONTH(dateOrdered)=12),0) as 'DEC'
FROM (
SELECT productId, YEAR(dateOrdered) AS YEAR FROM Product
GROUP BY YEAR(dateOrdered),ProductId) X

答案 2 :(得分:0)

您可以使用查询联合而不是临时表,也可以使用数据透视表选项。

以下是关于它的论坛讨论:

Sql Server Forums - Show the row-wise data as column-wise

答案 3 :(得分:0)

这有资格作为演示问题 演示文稿和SQL并不总是很好地混合。

在应用程序层中隔离您的表示逻辑:

  1. 节省您的维护时间 - 更改您的应用程序代码,但保持您的SQL完好无损;
  2. 使您能够更快地适应短暂的客户需求;
  3. 比摆弄一个交叉表或数据透视表让你更满意,这些表几乎完全符合你的想法。
  4. 下面是一个如何在Python中执行此操作的示例(您可以使用优秀的pyodbc模块连接到SQL Server):

    from collections import defaultdict
    from datetime import date
    
    dd = defaultdict(int)
    
    # input 
    rows = [(1,2,date(2008,10,10)), (1,1,date(2008,11,10)), 
            (1,2,date(2009,10,10)), (2,3,date(2009,10,12)), 
            (1,1,date(2009,10,15)), (2,2,date(2009,11,15))]
    
    for row in rows:
        # row[0] == productId
        # row[1] == Qty
        # row[2] == dateOrdered
        # pyodbc enables referring to column names by name
        dd[(row[2].year, row[2].month, row[0])] += row[1]
    
    presentation_rows = sorted(set((i[0], i[2]) for i in dd.keys()))
    
    for i in presentation_rows:
      print i[1], i[0], 
      for j in range(0,13):
        try:
          print dd[i[0], j, i[1]], 
        except IndexError:
          print 0,
      print
    
    # output
    # 1 2008 0 0 0 0 0 0 0 0 0 0 2 1 0
    # 1 2009 0 0 0 0 0 0 0 0 0 0 3 0 0
    # 2 2009 0 0 0 0 0 0 0 0 0 0 3 2 0
    

答案 4 :(得分:0)

对于使用Big Query的用户,您可以使用以下内容:

select *
from UNNEST(GENERATE_DATE_ARRAY('2015-10-01', '2019-10-01', INTERVAL 1 MONTH))

请参见https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators?hl=fr#generate_date_array

答案 5 :(得分:-1)

试试这个。因此,此代码将在特定时间范围内选择数据,然后将其转换为新列。例如,在我的sql代码中:它从列'L_dt'中选择'2014-10-01'和'2014-10-31'之间的时间范围,然后创建一个名为“October”的新列。通过这种方式,我们可以在源自一列的不同列中布置数据。

select 
sum(case when L_dt between '2014-10-01' and '2014-10-31' then 1 else 0 end) October,
sum(case when L_dt between '2014-11-01' and '2014-11-30' then 1 else 0 end) November,
sum(case when L_dt between '2014-12-01' and '2014-12-31' then 1 else 0 end) December
from Table; 

如果输入如下:    L_dt
2014年10月13日 情节中字 情节中字 2014年10月

然后输出

+---------+----------+----------+
| October | November | December |
+---------+----------+----------+
|    2    |    1     |    1     |
+---------+----------+----------+