SQL显示两个日期之间的月份和年份数

时间:2014-01-29 15:56:23

标签: sql sql-server date

我有一个表格,显示产品的开始日期和结束日期。我在表格中有总价值和产品名称。我希望能够显示两个日期之间的月份和年份,同时包括产品名称和该时间段内的平均值。我一直在尝试使用一个解决单个产品问题的查询。我需要在多个产品中显示结果。我收到一条错误消息,说我无法查询子查询中的多个项目。有可能得到我正在寻找的结果吗?谢谢您的帮助。非常感谢。

SQL to display both month and year between two dates

产品数据示例

    Product    Value Start Date End Date
    Widget A    100 1/1/2012    5/1/2013
    Widget B    500 2/1/2010    6/1/2012

期望的结果

    Product     Date       Month Year    Value
    Widget A    1/1/2012    Jan 2012     5.88 
    Widget A    2/1/2012    Feb 2012     5.88 
    Widget A    3/1/2012    Mar 2012     5.88 
    Widget A    4/1/2012    Apr 2012     5.88 
    Widget A    5/1/2012    May 2012     5.88 
    Widget A    6/1/2012    Jun 2012     5.88 
    Widget A    7/1/2012    Jul 2012     5.88 
    Widget A    8/1/2012    Aug 2012     5.88 
    Widget A    9/1/2012    Sep 2012     5.88 
    Widget A    10/1/2012   Oct 2012     5.88 
    Widget A    11/1/2012   Nov 2012     5.88 
    Widget A    12/1/2012   Dec 2012     5.88 
    Widget A    1/1/2013    Jan 2013     5.88 
    Widget A    2/1/2013    Feb 2013     5.88 
    Widget A    3/1/2013    Mar 2013     5.88 
    Widget A    4/1/2013    Apr 2013     5.88 
    Widget A    5/1/2013    May 2013     5.88 
    Widget B    2/1/2010    Feb 2010     17.24 
    Widget B    3/1/2010    Mar 2010     17.24 
    Widget B    4/1/2010    Apr 2010     17.24 
    Widget B    5/1/2010    May 2010     17.24 
    Widget B    6/1/2010    Jun 2010     17.24 
    Widget B    7/1/2010    Jul 2010     17.24 
    Widget B    8/1/2010    Aug 2010     17.24 
    Widget B    9/1/2010    Sep 2010     17.24 
    Widget B    10/1/2010   Oct 2010     17.24 
    Widget B    11/1/2010   Nov 2010     17.24 
    Widget B    12/1/2010   Dec 2010     17.24 
    Widget B    1/1/2011    Jan 2011     17.24 
    Widget B    2/1/2011    Feb 2011     17.24 
    Widget B    3/1/2011    Mar 2011     17.24 
    Widget B    4/1/2011    Apr 2011     17.24 
    Widget B    5/1/2011    May 2011     17.24 
    Widget B    6/1/2011    Jun 2011     17.24 
    Widget B    7/1/2011    Jul 2011     17.24 
    Widget B    8/1/2011    Aug 2011     17.24 
    Widget B    9/1/2011    Sep 2011     17.24 
    Widget B    10/1/2011   Oct 2011     17.24 
    Widget B    11/1/2011   Nov 2011     17.24 
    Widget B    12/1/2011   Dec 2011     17.24 
    Widget B    1/1/2012    Jan 2012     17.24 
    Widget B    2/1/2012    Feb 2012     17.24 
    Widget B    3/1/2012    Mar 2012     17.24 
    Widget B    4/1/2012    Apr 2012     17.24 
    Widget B    5/1/2012    May 2012     17.24 
    Widget B    6/1/2012    Jun 2012     17.24 

2 个答案:

答案 0 :(得分:1)

您需要交叉加入数字/日期表。

如果你没有,那么使用系统表和ROW_NUMBER()

动态创建它们相对便宜
WITH Product AS
(   SELECT  Product, 
            Value = CAST(Value AS DECIMAL(10, 2)), 
            StartDate = CAST(StartDate AS DATE), 
            EndDate = CAST(EndDate AS DATE)
    FROM    (VALUES
                ('Widget A', 100, '20120101', '20130501'),
                ('Widget b', 500, '20100201', '20120601')
            ) t (Product, Value, StartDate, EndDate)
), Numbers AS
(   SELECT  Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
    FROM    sys.all_objects a
)
SELECT  p.Product,
        d.[Date],
        MonthYear = LEFT(DATENAME(MONTH, d.[Date]), 3) + ' ' + DATENAME(YEAR, d.[Date]), 
        Value = CAST(p.Value / (1 + DATEDIFF(MONTH, p.StartDate, p.EndDate)) AS DECIMAL(5, 2))
FROM    Product p
        CROSS JOIN Numbers n
        OUTER APPLY (SELECT Date = DATEADD(MONTH, n.Number, p.StartDate)) d
WHERE   d.[Date] <= p.EndDate
ORDER BY p.Product, [Date];

<强> Example on SQL Fiddle

关于生成和使用数字/日期表的一些进一步阅读,无论是静态还是动态,请看一下这个系列:

答案 1 :(得分:0)

第一步,获取日期列表。输出中的每月日期必须来自某个地方 ...这就是SQL的工作方式。创建和维护“日历表”非常常见,但也有其他方法。

CREATE TABLE months ([Date] date)
--Populate table with a list of first-of-months

SELECT
  p.[Product],
  m.[Date],
  LEFT(DATENAME(month,m.[Date]),3) AS [Month]
  YEAR(m.[Date]) AS [Year]
  p.[Value]/(DATEDIFF(month,p.[Start Date],p.[End Date])+1) AS [Value]
FROM months m
INNER JOIN products p ON (m.[Date] BETWEEN p.[Start Date] AND p.[End Date])