T-SQL NULL-Friendly查询

时间:2014-09-08 09:57:14

标签: sql sql-server null

我在Microsoft T-SQL中有一个表“tblSalesOrder”,带有一些示例记录:

SalesOrderID    OrderDate    ItemID    Quantity   PromotionCode
====================================================================
1               2014-09-01   100       5          NULL
2               2014-09-01   120       10         ABC
3               2014-09-05   150       7          NULL
4               2014-09-08   200       15         NULL

我需要为不存在的记录返回NULL友好的结果集。

例如,我想要查看2014年9月的每月查询:

SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM tblSalesOrder
WHERE OrderDate = BETWEEN '2014-09-01' AND '2014-09-30'

我需要它每天至少返回1行(如果当天的条目不可用,则为0值行)

SalesOrderID    OrderDate    ItemID    Quantity   PromotionCode
====================================================================
1               2014-09-01   100       5          NULL
2               2014-09-01   120       10         ABC
0               2014-09-02   0         0          0
0               2014-09-03   0         0          0
0               2014-09-04   0         0          0
3               2014-09-05   150       7          NULL
0               2014-09-06   0         0          0
0               2014-09-07   0         0          0
4               2014-09-08   200       15         NULL
0               2014-09-09   0         0          0
    ...
    ...
    ...
0               2014-09-30   0         0          0

3 个答案:

答案 0 :(得分:2)

master..spt_values是包含2506行的所有microsoft sql数据库中的表,通过交叉连接,它将有2506 * 2506行来计算from和to之间的日期。也可以使用其他表,这只是用于创建日期的表。日历表甚至更容易使用。

EXCEPT将删除所有已使用的日期。然后通过将来自tblSalesOrder和CTE的行与union all组合在一起,空日将填充所需的硬编码值:

DECLARE @from date = '2014-09-01'
DECLARE @to date   = '2014-09-30'

;WITH CTE as
(
  SELECT top (case when @to < @from then 0 else datediff(day, @from, @to) + 1 end)
    dateadd(day, row_number() over (order by (select 1)) - 1, @from) OrderDate
  FROM 
    master..spt_values t1
  CROSS JOIN 
    master..spt_values t2
  EXCEPT
  SELECT 
    OrderDate
  FROM 
    tblSalesOrder
)
SELECT 
  0 SalesOrderID, OrderDate, 0 ItemID, 0 Quantity, '0' PromotionCode
FROM
  CTE
UNION ALL
SELECT
  SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM
  tblSalesOrder
ORDER BY
  OrderDate, SalesOrderId

答案 1 :(得分:1)

您可以joinselectcoalesce中的日期参数:

select coalesce(t.SalesOrderID, 0) SalesOrderID
,      coalesce(t.OrderDate, d.OrderDate) OrderDate
,      coalesce(t.ItemID, 0) ItemID
,      coalesce(t.Quantity, 0) Quantity
,      coalesce(t.PromotionCode, 0) PromotionCode
from   (select @dateParameter OrderDate) d
left
outer
join   ( SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
         FROM tblSalesOrder
       ) t
on     t.OrderDate = d.OrderDate

答案 2 :(得分:1)

DECLARE @startDate date= '20140901'
    ,@endDate date = '20140930';

WITH Calendar as (
    SELECT @startDate as OrderDate
    UNION ALL
    SELECT DATEADD(DAY, 1, OrderDate) as OrderDate
    FROM Calendar
    WHERE OrderDate < @endDate
)

SELECT coalesce(t.SalesOrderID, 0) SalesOrderID
,      coalesce(t.OrderDate, Calendar.OrderDate) OrderDate
,      coalesce(t.ItemID, 0) ItemID
,      coalesce(t.Quantity, 0) Quantity
,      CASE WHEN t.OrderDate IS NULL THEN  '0' ELSE t.PromotionCode END as PromotionCode    FROM Calendar
    LEFT JOIN tblSalesOrder t ON Calendar.OrderDate = t.OrderDate
ORDER BY Calendar.OrderDate, t.SalesOrderID
OPTION (MAXRECURSION 0);