【问题标题】:Get count of consecutive days meeting a given criteria获取满足给定条件的连续天数
【发布时间】:2015-06-09 07:35:37
【问题描述】:

我的 Oracle 数据库中有以下结构:

Date          Allocation  id
2015-01-01    Same        200
2015-01-02    Good        200
2015-01-03    Same        200
2015-01-04    Same        200
2015-01-05    Same        200
2015-01-06    Good        200

我想要一个查询,它只需要检查前连续几天并获取分配为"Same" 的计数。

我想按日期选择,例如2015-01-05
示例输出:对于日期2015-01-05,计数为3

新问题。通过 Lukas Eder 的查询,计数始终为 12。但预期是3。为什么?!

Date          Allocation  id
2015-01-01    Same        400
2015-01-02    Good        400
2015-01-03    Same        400
2015-01-04    Same        400
2015-01-05    Same        400
2015-01-06    Good        400

来自 Lukas Eder 的代码

 SELECT c
    FROM (
      SELECT allocation, d, count(*) OVER (PARTITION BY allocation, part ORDER BY d) AS c
      FROM (
        SELECT allocation, d,
               d - row_number() OVER (PARTITION BY allocation ORDER BY d) AS part
        FROM t
      )
    )
    WHERE d = DATE '2015-01-05';

预期的输出是这样的,First_day end Last day 不需要:

id   count    first_day   Last_Day
200  3        2015-01-03  2015-01-05
400  3        2015-01-03  2015-01-05

【问题讨论】:

  • 您能告诉我们您尝试过的查询吗?
  • 查看滞后和领先函数

标签: sql oracle


【解决方案1】:

此查询将产生每一行的计数:

SELECT allocation, d, count(*) OVER (PARTITION BY allocation, part ORDER BY d) AS c
FROM (
  SELECT allocation, d,
         d - row_number() OVER (PARTITION BY allocation ORDER BY d) AS part
  FROM t
)
ORDER BY d;

然后您可以对其进行过滤以查找给定行的计数:

SELECT c
FROM (
  SELECT allocation, d, count(*) OVER (PARTITION BY allocation, part ORDER BY d) AS c
  FROM (
    SELECT allocation, d,
           d - row_number() OVER (PARTITION BY allocation ORDER BY d) AS part
    FROM t
  )
)
WHERE d = DATE '2015-01-05';

说明:

派生表用于计算每个日期和分配的不同“分区”part

  SELECT allocation, d,
         d - row_number() OVER (PARTITION BY allocation ORDER BY d) AS part
  FROM t

结果是:

allocation  d           part
--------------------------------
Same        01.01.15    31.12.14
Good        02.01.15    01.01.15
Same        03.01.15    01.01.15
Same        04.01.15    01.01.15
Same        05.01.15    01.01.15
Good        06.01.15    04.01.15

part 产生的具体日期无关紧要。只是某个日期对于分配中的每个“组”日期都是相同的。然后您可以使用count(*) over(...) 窗口函数计算(allocation, part) 相同值的数量:

SELECT allocation, d, count(*) OVER (PARTITION BY allocation, part ORDER BY d) AS c
FROM (...)
ORDER BY d;

产生你想要的结果。

数据

我使用了下表作为示例:

CREATE TABLE t AS (
  SELECT DATE '2015-01-01' AS d, 'Same' AS allocation FROM dual UNION ALL
  SELECT DATE '2015-01-02' AS d, 'Good' AS allocation FROM dual UNION ALL
  SELECT DATE '2015-01-03' AS d, 'Same' AS allocation FROM dual UNION ALL
  SELECT DATE '2015-01-04' AS d, 'Same' AS allocation FROM dual UNION ALL  
  SELECT DATE '2015-01-05' AS d, 'Same' AS allocation FROM dual UNION ALL
  SELECT DATE '2015-01-06' AS d, 'Good' AS allocation FROM dual
);

【讨论】:

  • @MeesvanZ:哦,我忽略了“前一个”位。我通过将ORDER BY d 添加到COUNT(*) OVER (...) 窗口函数来调整查询。是不是更像?否则,通常最好在问题中显示预期输出以避免任何疑问。
  • 请再看我的帖子,真的需要你的帮助
  • @MeesvanZ:预期的输出是什么?请问,你能在你的问题中添加预期的输出吗?
  • @MeesvanZ:伙计,你完全改变了这个问题!这很令人困惑。在某些时候,我的回答是正确的(我相信两次)。请问,你能让这个问题保持一致吗?请尝试在未来从一开始就提出一个更一致的问题。另一种选择是不要不一致地编辑问题,而是接受正确的答案(就问题而言是正确的)并提出一个新的、单独的问题。
  • 我同意@LukasEder
【解决方案2】:

考虑以下查询来解决您的问题:

SELECT COUNT(*) AS `count` FROM test t
WHERE `date` < '2015-01-05' AND allocation = 'Same';

假设给定日期是“2015-01-05”。这里的想法是选择所有小于“2015-01-05”的日期,这意味着它的前几天。由于分配必须是“相同的”,因此它也包含在语句的条件部分中。

【讨论】:

    【解决方案3】:

    试试这个:

    SELECT  count(Allocation) as total_allocation FROM table_name 
    WHERE (Date BETWEEN CURDATE() - INTERVAL 1 DAY AND CURDATE()) 
    AND (Allocation='Same');
    

    这将获取今天日期之前的所有记录,并且其 Allocation='Same'

    【讨论】:

      【解决方案4】:

      这更容易:

      DEMO

      SELECT count(*) AS c
      FROM t
      WHERE d <
      TO_DATE (
             '2015-01-05'
              ,'yyyy-mm-dd'
      )
      AND allocation = 'Same';
      

      【讨论】:

      • 此查询将返回“相同”记录的总计数,而不是连续天数。在您的示例中,结果是 3 而不是 4,只是因为日期过滤器“小于”并且不计入 2015-01-05
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      • 1970-01-01
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多