【问题标题】:SQL Date rows for inactivity days不活动天数的 SQL 日期行
【发布时间】:2012-09-10 12:17:12
【问题描述】:

假设有这张表存储每天的访问者数量。

当我想查询表格并从中创建图表时,就会出现问题。

没有活动的日子在表格上没有对应的行。

例如

Day1 - 7
Day2 - 8
Day4 - 7

而且生成的图表是不正确的。因为第 3 天需要 0。

现在,不使用 SQL 以外的任何东西就可以为不活动的日子创建这些值吗?

我想创建另一个表,它会在每次执行脚本时创建 30 天的所有日期,并且问题会得到解决,但我想知道是否有更实用的解决方案。

提前致谢。

【问题讨论】:

  • SQL Server? MySQL?还有什么?
  • stackoverflow.com/questions/75752/… 的可能重复项 - 这个问题在 SO 上被问了很多。一般来说,答案是加入一个包含所有日期的临时表,或者处理应用程序逻辑中的缺失值。
  • 另一个和这个类似的问题:stackoverflow.com/questions/2670183/…
  • 感谢大家的回复,实际上我以不同的方式解决了这个问题,使用字典类,添加所有值,然后每天检查该日期的值是否存在,如果不存在的话假定为 0。但这不是“仅使用 sql”

标签: sql gaps-and-islands


【解决方案1】:

你用 30 天创建表的解决方案是一个非常简单实用的解决方案。

如果你真的想的话,你可以在没有额外桌子的情况下这样做,但这并不令人愉快。 SQL 并不是真正设计为允许您选择数据库中不存在的数据。一般来说,一个更简单的解决方案是在客户端添加缺失的行,而不是尝试编写复杂的 SQL 语句来执行此操作。

【讨论】:

    【解决方案2】:

    您可以尝试使用 Sql Server 2005+ 和 CTE Recursive (Using Common Table Expressions)

    DECLARE @Table TABLE(
            DateVal DATETIME,
            Visists INT
    )
    
    INSERT INTO @Table SELECT '01 Jan 2010', 10
    INSERT INTO @Table SELECT '03 Jan 2010', 1
    INSERT INTO @Table SELECT '05 Jan 2010', 30
    INSERT INTO @Table SELECT '10 Jan 2010', 50
    
    ;WITH MinMax AS (
            SELECT  MIN(DateVal) Startdate,
                    MAX(DateVal) EndDate
            FROM    @Table
    ),
    DateRange AS(
            SELECT  StartDate DateVal
            FROM    MinMax
            UNION ALL
            SELECT  DateRange.DateVal + 1
            FROM    DateRange,
                    MinMax
            WHERE   DateRange.DateVal + 1 <= MinMax.EndDate
    )
    SELECT  DateRange.DateVal,
            ISNULL(t.Visists,0) TotalVisits
    FROM    DateRange LEFT JOIN
            @Table t ON DateRange.DateVal = t.DateVal
    

    输出为

    DateVal                 TotalVisits
    ----------------------- -----------
    2010-01-01 00:00:00.000 10
    2010-01-02 00:00:00.000 0
    2010-01-03 00:00:00.000 1
    2010-01-04 00:00:00.000 0
    2010-01-05 00:00:00.000 30
    2010-01-06 00:00:00.000 0
    2010-01-07 00:00:00.000 0
    2010-01-08 00:00:00.000 0
    2010-01-09 00:00:00.000 0
    2010-01-10 00:00:00.000 50
    

    【讨论】:

      【解决方案3】:

      我不会只调用这个 SQL,因为它使用 PostgreSQL 特定的函数 - 但在您使用的任何数据库中都可能有类似的东西。

      PostgreSQL 有个不错的功能:generate_series

      您可以使用此功能创建一系列 30 天。

      select current_date + s.a as dates from generate_series(0,30) as s(a);
      
       dates    
      ------------
       2010-04-22
       2010-04-23
       2010-04-24
       (.. etc ..)
      

      然后您可以在查询中使用它,例如:

      select vpd.visits, temp.dates
        from (select current_date + s.a as dates from generate_series(0,30) as s(a)) as temp
       left outer join visits_per_day vpd on vpd.day = temp.dates
      
       visits |   dates    
      --------+------------
           10 | 2010-04-22
              | 2010-04-23
           20 | 2010-04-24
              | 2010-04-25
              | 2010-04-26
           30 | 2010-04-27
      

      【讨论】:

        【解决方案4】:

        不,没有标准方法仅使用 SQL 将不确定数量的缺失行添加到 SQL 查询的结果中,而无需先将这些行存储在表中。

        您可以有一个表,其中包含您的应用程序将运行的所有日期,也可以有一个表,您可以只将当前查询将使用的日期放入其中。如果您选择第二种解决方案,请记住计划让不同用户同时在不同日期范围内执行相同的查询——如果您的 DBMS 支持,您将希望表是临时的和特定于用户的。

        【讨论】:

          猜你喜欢
          • 2017-11-26
          • 1970-01-01
          • 2018-09-27
          • 2017-08-16
          • 2018-03-27
          • 1970-01-01
          • 2023-03-08
          • 1970-01-01
          • 2022-06-10
          相关资源
          最近更新 更多