【问题标题】:DB2: Display the 7 days starting from last saturday, including days in the futureDB2:显示从上周六开始的 7 天,包括未来的几天
【发布时间】:2015-04-18 09:38:21
【问题描述】:

到目前为止我有什么:

这个查询:

SELECT to_char(creationdate, 'DD-MM-YY') AS DATE
    ,sum(CASE 
            WHEN internalpriority >= 3
                THEN 1
            ELSE 0
            END) AS

CLOSE
FROM incident
WHERE creationdate BETWEEN (
                SELECT DISTINCT (CURRENT_timestamp - (DAYOFWEEK(CURRENT_timestamp) - 0) DAYS - (hour(current_timestamp)) hours - (minute(current_timestamp)) minute) AS MONDAY_OF_CURRENT_WEEK_DATE
                FROM incident
                )
        AND (
                SELECT DISTINCT (CURRENT_timestamp - (DAYOFWEEK(CURRENT_timestamp) - 6) DAYS - (hour(current_timestamp)) hours - (minute(current_timestamp)) minute) AS MONDAY_OF_CURRENT_WEEK_DATE
                FROM incident
                )
GROUP BY to_char(creationdate, 'DD-MM-YY')

得到这个结果(今天是 17 号,所以 14 号是上周六,到目前为止一切都很好)

14-02-15    307
15-02-15    296
16-02-15    687
17-02-15    357

但我也需要

18-02-15     0
19-02-15     0
20-02-15     0

哪些是未来,但如何......

【问题讨论】:

  • 解决此问题的最佳方法是使用日历表,您可以在其中有一个未来每一天的条目,您可以简单地加入您的事务表。如果您的数据架构师完全反对创建这样的表格,您可以使用表格表达式为您生成日期列表。

标签: sql db2 dayofweek


【解决方案1】:

我暴力破解它,它有效,如果您知道更优雅的方式,请发表评论,他们已经开始在这里称我为弗兰肯斯坦博士 :(

select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 0 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 0 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 1 days), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 1 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 2 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 2 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 3 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 3 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 4 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 4 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 5 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 5 days ), 'DD-MM-YY')
union
select distinct to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 6 days ), 'DD-MM-YY') as date, count(ticketid) from incident where to_char(creationdate, 'DD-MM-YY') = to_char((current_timestamp - ( DAYOFWEEK(CURRENT_timestamp)) DAYS + 6 days ), 'DD-MM-YY')

【讨论】:

    【解决方案2】:

    首先,如果您正在处理时间戳,don't use BETWEEN。作为一个积极的、连续范围的类型,包含上限会产生不正确的结果(博客文章专门关于 SQL Server 和日期/时间/时间戳类型,但问题实际上是由于数字的表示方式)。

    接下来,您尝试按天分组,但通过强制转换为字符这样做会阻止数据库使用索引来完成查询的那部分。

    所以我们想要的是范围查询。我们将使用递归 CTE 来构建要使用的日期集,但您也可以使用日历表(毫无疑问,这可能是构建的最佳分析表)。

    WITH Date_Range AS (SELECT start AS incidentDate, 1 AS daysElapsed,
                               TIMESTAMP(start) AS dayStart, 
                               TIMESTAMP(start + 1 DAY) AS dayEnd
                        FROM (VALUES(CURRENT_DATE
                                      - (DAYOFWEEK_ISO(CURRENT_DATE) + 1) DAYS)) T(start)
                        UNION ALL
                        SELECT incidentDate + 1 DAY, daysElapsed + 1, 
                               dayEnd, dayEnd + 1 DAY
                        FROM Date_Range
                        WHERE daysElapsed < 7)
    
    SELECT incidentDate, COUNT(Incident.internalPriority) AS close
    FROM Date_Range
    LEFT JOIN Incident
           ON Incident.internalPriority >= 3
              AND Incident.creationDate >= Date_Range.dayStart
              AND Incident.creationDate < Date_Range.dayEnd
    GROUP BY incidentDate
    

    (未测试,因为我缺少一个可以使用的 DB2 实例。不过应该很接近)

    请注意:

    • 我使用了DAYOFWEEK_ISO(...),因为原版DAYOFWEEK(...) 会根据当前的文化背景给出不同的结果(即,您显然期望星期日为1,但许多非美国文化使用星期一作为第一天一周中的...)。这样做可以消除潜在的问题。
      哦,如果它当前是星期六,它仍然可以追溯到一周,我认为这是预期的行为。
    • 代码假定creationDate 是一个绝对(UTC) 时间戳,而不是本地时间戳(带有时区)。如果不是这种情况,您需要进行更改。

    您的原始查询存在以下问题:
    SUM(CASE WHEN internalPriority >= 3
             THEN 1
             ELSE 0 END)
    

    ...有时,这种事情是获取此信息的唯一方法。问题是它可能需要进行表扫描(数据库需要读取internalPriority 的所有值才能运行CASE)。通常最好将其设置为连接或其他过滤条件,这将允许它通过索引进行检查(假设您有可以使用的东西)。

    SELECT DISTINCT (CURRENT_timestamp - (DAYOFWEEK(CURRENT_timestamp) - 0) DAYS - (HOUR(current_timestamp)) HOURS - (MINUTE(current_timestamp)) MINUTE) AS MONDAY_OF_CURRENT_WEEK_DATE
    FROM Incident
    

    ...好吧:

    1. 您遍历表中的每一行,对每一行执行日期数学运算(返回一个恒定的结果),然后因为DISTINCT 而丢弃大部分数据。哎哟。如果您需要单行,请使用VALUES(...) 或现有的单行虚拟表 (sysibm/sysdummy1) 构建它。

    2. 您会错过秒数和小数秒。行最终将分配给错误的日期。幸运的是,CURRENT_TIMESTAMP 返回的类型忽略了 DST/时区(本质上是 UTC),或者您一直使用寄存器的事实可能会改变您查看的日期。

      之间

    请不要使用这个。对于除整数 count 之外的任何内容,您都需要独占上界(&lt; - 用于正值)或独占下界(&gt; - 负值)。请勿将其与整数一起使用以保持一致性。

    GROUP BY TO_CHAR(creationdate, 'DD-MM-YY')
    

    ...正如我已经提到的,对函数调用的结果进行分组将阻止数据库使用索引来完成您的查询。尽可能避免这样的行为(无论如何,格式化确实是在显示层代码中要做的事情)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-03
      • 2018-12-25
      • 2013-12-23
      • 2019-11-21
      相关资源
      最近更新 更多