通过日期范围选择结果,包括不存在结果的null

时间:2015-08-11 14:35:47

标签: php sql-server

这是Microsoft SQL,而不是Mysql。

我有一张表格,其中包含发送给客户的货件的发票数据。

例如,数据可能如下所示:

INVOICE DATE | QUANTITY | PRODUCT | VENDOR ID
2014-07-31   | 25       | Oranges | 12
2014-08-12   | 14       | Apples  | 12
2014-09-01   | 135      | Oranges | 12
2015-07-04   | 18       | Oranges | 12
2015-07-12   | 35       | Apples  | 12

如您所见,数据中存在空白,我们未在特定月份向该客户发送订单。

我试图得到一个月的列表,所以我可以在图表上显示它(chartJS是具体的)所以我需要空值,这些记录不存在所以我们有一个12个值的字符串,即使它们&# 39;在给定年份全部为零。

现在,我们在PHP循环中使用不同的查询(非常糟糕)来实现这一点,就像这样

while($i = 1; $i < 13; $i++) {
    $query = "Select sum(quantity), month, year
        From Table
        where month = $i
        and year = $year
        and vendorID = 12"
}

这导致产生如下的数据集,我们每个月得到一个数据集,如果没有结果,我们得到零。

month | year | quantity
...   | ...  | ...
6     | 2014 | 0
7     | 2014 | 25
8     | 2014 | 14
9     | 2014 | 135
10    | 2014 | 0
....  | .... | ....

不幸的是,这需要我们想要显示的每年12个查询。我希望能够在一个查询中获得相同的数据。

不幸的是,更新的查询仅在发票日期存在时返回结果。有没有办法使用SQL而不是PHP来循环所有可能的月份,以便使用聚合查询来获取此信息?

我已经得到以下查询,但它只给出了发票日期存在的结果:

Select sum(quantity), month, year
from table where VendorID = 12
and InvoiceDate between '1/1/2014' and '12/31/2014'
GROUP BY year, month

结果:

Quantity | Month | Year
25       | 7     | 2014
14       | 8     | 2014
135      | 9     | 2014
53       | 7     | 2015

正如您所看到的,这仅提供带有值的结果,而不是带有零的所有月份。

解决方案

感谢贡献者,我有一个有效的解决方案查询,是两种建议的组合

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
Set @StartDate = '7/1/2014'
SET @EndDate = '12/1/2015'

;with cal as (
    SELECT @StartDate AS [Date]
    UNION ALL 
    SELECT DATEADD(month, 1, [Date])
    FROM cal
    WHERE [Date] < @EndDate
)
select coalesce(a.qty, 0) as qty, 
DATEPART(month, cal.[Date]) AS [month], 
DATEPART(year, cal.[Date]) AS [year] from
(
    SELECT sum(qty) as qty, 
    [month], 
    [year]
    from ship_table
    WHERE vendorID = 12
    group by [year], [month]
) A
right join cal ON DATEPART(month, cal.[Date])=A.[month]
AND DATEPART(year, cal.[Date])=A.[year]

2 个答案:

答案 0 :(得分:2)

请尝试以下查询。我已使用数据透视表填写月份数字。 我假设年份保持不变,即2014(证明使用ISNULL(year,2014))或者可以通过某种方式从YEAR(@startmonth)

等参数推导出来

我还为demo创建了一个sql小提琴: http://sqlfiddle.com/#!6/9dc17/2

select ISNULL(A.quantity,0) as quantity,cal.Num as Month,ISNULL(year,2014) from
(Select sum(quantity) as quantity, month(InvoiceDate) as month, year(InvoiceDate) as year
from [table]
where VendorID = 12
and InvoiceDate between '1/1/2014' and '12/31/2014'
GROUP BY year(InvoiceDate), month(InvoiceDate)) A
right join
(select mon,num from
    (
    select 1 as [Jan],2 as [feb],3 as [mar],4 as  [apr],5 as [may],6 as [jun],7 as [jul],8 as [aug],9 as [sep],10 as [oct],11 as [nov],12 as [dec]) s
    UNPIVOT
    (
    Num for Mon in ([jan],[feb],[mar],[apr],[may],[jun],[jul],[aug],[sep],[oct],[nov],[dec])
    )up) cal
    on A.month=Cal.Num

答案 1 :(得分:2)

以下是我开车的答案。

根据您问题中的查询代码,我假设您的表中包含名为&#34; Month&#34;和&#34;年&#34;,它们的使用方法与查询相同。

假设您将StartDate和EndDate参数传递给您的查询,那么您可以获得任何日期范围:

WITH cte AS (
  SELECT @StartDate AS [Date]
  UNION ALL 
  SELECT DATEADD(month, 1, [Date])
  FROM cte
  WHERE [Date] <= @EndDate
)
Select 
  sum(quantity), 
  DATEPART(month, cte.[Date]) AS [month], 
  DATEPART(year, cte.[Date]) AS [year]
from table t
RIGHT OUTER JOIN cte
  ON DATEPART(month, cte.[Date])=t.month
  AND DATEPART(year, cte.[Date])=t.year
where VendorID = 12
GROUP BY   DATEPART(month, cte.[Date]) AS [month], 
  DATEPART(year, cte.[Date]) AS [year]