如何从select语句返回任何行时返回默认值

时间:2014-03-04 15:48:37

标签: sql sql-server

我有一个select语句,它返回两列,一个日期列和一个count(value)列。当count(value)列没有任何记录时,我需要它返回0.目前,它只是一起跳过该日期记录。

以下是查询的基础知识。

select convert(varchar(25), DateTime, 101) as recordDate,
       count(Value) as recordCount
from History
where Value < 700
group by convert(varchar(25), DateTime, 101)

以下是我得到的一些结果。

+------------+-------------+
| recordDate | recordCount |
+------------+-------------+
| 02/26/2014 | 143         |
| 02/27/2014 | 541         |
| 03/01/2014 | 21          |
| 03/02/2014 | 60          |
| 03/03/2014 | 113         |
+------------+-------------+

请注意它跳过2014年2月28日。这是因为count(value)列没有任何可计数的内容。如何在日期为2014年2月28日的日期添加记录,recordCount为0?

7 个答案:

答案 0 :(得分:2)

要为缺少日期生成行,您可以将数据加入date dimension table

它看起来像这样:

select convert(varchar(25), ddt.DateField, 101) as recordDate,
       count(t.Value) as recordCount
from History h
right join dbo.DateDimensionTable ddt
    on ddt.DateField = convert(varchar(25), h.DateTime, 101)
where h.Value < 700
group by convert(varchar(25), h.DateTime, 101)

如果您的表使用DateTime列仅存储日期(意味着时间总是午夜),那么您可以替换此

right join dbo.DateDimensionTable ddt
    on ddt.DateField = convert(varchar(25), h.DateTime, 101)

用这个

right join dbo.DateDimensionTable ddt
    on ddt.DateField = h.DateTime

答案 1 :(得分:0)

您可以使用COUNT(*)。如果没有找到任何列,它将返回零。如果需要,您也可以按值列对结果集进行分组。

答案 2 :(得分:0)

select convert(varchar(25), DateTime, 101) as recordDate,
       CASE WHEN count(value) =0 THEN 0 ELSE COUNT(value) END  recordCount
from History
where Value < 700
group by convert(varchar(25), DateTime, 101)

答案 3 :(得分:0)

使用group by时,它只会创建记录中存在的不同值列表。由于20140228没有记录,因此不会出现在该组中。

您最好的办法是生成一个值列表,您的案例中的日期,以及左键加入或将该表应用于您的历史记录表。

我似乎无法复制我的T-SQL,所以这里是一个哈希宾。

http://hastebin.com/winaqutego.vbs

答案 4 :(得分:0)

最佳做法是让您拥有一个数据集市,其中日期的单独维度表与您可能感兴趣的所有日期保持一致 - 即使它们缺少金额。 DMason的答案显示了具有这种维度表的查询。

为了与最佳实践保持一致,您将拥有一个事实表,您可以将这些历史数据保存在您需要的粒度级别(每天,在本例中),因此您不需要GROUP BY除非你需要更粗糙的粒度(每周,每月,每年)。

在您的运营数据库和数据集市数据库中,日期将存储为日期,而不是......

但是,那么,既然这是现实世界,你可能无法改变其他人所做的......如果你:a)只关心[历史]中出现的日期,b)这些日期永远不会以小时/分钟存储;然后跟随查询可能是您需要的:

SELECT MyDates.DateTime, COUNT(*)-1 AS RecordCount
FROM (
      SELECT DISTINCT DateTime FROM History
   ) MyDates
LEFT JOIN History H
  ON  MyDates.DateTime = H.Datetime
  AND H.Value < 700
GROUP BY MyDates.DateTime

尝试在DateTime上添加索引,并使用最早/最晚的日期进一步约束查询,以获得更好的性能结果。

答案 5 :(得分:0)

我同意Dates表(AKA时间维度)是正确的解决方案,但有一个更简单的选项:

SELECT
    CONVERT(VARCHAR(25), DateTime, 101) AS RecordDate,
    SUM(CASE WHEN Value < 700 THEN 1 ELSE 0 END) AS RecordCount
FROM
    History
GROUP BY
    CONVERT(VARCHAR(25), DateTime, 101)

答案 6 :(得分:-1)

试试这个:

DECLARE @Records TABLE (
    [RecordDate] DATETIME,
    [RecordCount] INT
)

DECLARE @Date DATETIME = '02/26/2014' -- Enter whatever date you want to start with
DECLARE @EndDate DATETIME = '03/31/2014' -- Enter whatever date you want to stop
WHILE (1=1)
BEGIN
    -- Insert the date into the temp table along with the count
    INSERT INTO @Records (RecordDate, RecordCount) 
    VALUES (CONVERT(VARCHAR(25), @Date, 101), 
            (SELECT COUNT(*) FROM dbo.YourTable WHERE RecordDate = @Date))

    -- Go to the next day
    @Date = DATEADD(d, 1, @Date)

    -- If we have surpassed the end date, break out of the loop
    IF (@Date > @EndDate) BREAK;
END

SELECT * FROM @Records

如果您的日期有时间组件,则需要修改此日期以检查SELECT COUNT(*)...查询中的开始和结束日期。