1

我正在尝试显示每个费率以及开始和结束日期的笼子数量。这将进入发票,我们每天为每个笼子开具账单,这些笼子可以有不同的费率。

这不是一个简单GROUP BY的获取MINMAX日期,因为笼子的数量可以下降或上升,然后再次回到相同的数字,所以我只需要查看连续数据。

我搜索了一个解决方案并找到了这个答案。我对其进行了一些修改以满足我的需要并提出了这个

WITH cte(rate_name, cages, use_date) AS (
  SELECT 'I1',      8, DATE'2017-11-04' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-05' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-07' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-10' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-11' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-12' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-13' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-14' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-01' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-02' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-03' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-04' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-05' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-06' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-07' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-08' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-09' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-10' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-11' FROM DUAL
)

SELECT
  a.rate_name,
  a.cages,
  MIN(a.use_date) AS startdate,
  MAX(a.use_date) AS enddate
FROM (
  SELECT
    cte.use_date,
    cte.rate_name,
    cte.cages,
    ROW_NUMBER() OVER (ORDER BY cte.rate_name, cte.use_date) - ROW_NUMBER() OVER (PARTITION BY cte.rate_name, cte.cages ORDER BY cte.use_date) AS grp
  FROM cte
) a
GROUP BY a.rate_name, a.cages, a.grp
ORDER BY a.rate_name ASC, 3;

我在 PL/SQL 中运行了这个查询,它似乎非常适合我想要做的事情。当我尝试在我们正在使用的软件工具中插入解决方案时,结果发现它不支持ROW_NUMBER()OVERPARTITION BY.

有没有一种方法可以在不必使用这些内置功能的情况下获得相同的结果?

我已经开始考虑ROW_NUMBER()手动实施并找到了这种方法。当我测试它时它似乎有效,但我并没有真正插入它。我现在有点坚持实施PARTITION BY,我只是觉得有点失落,不知道我是否朝着正确的方向前进。

编辑

我刚刚注意到查询返回了不正确的结果。

对于I1带有7笼子的情况,应该返回 2 行。第一行开始并结束于2017-11-07,而第二行开始于2017-11-10并结束于2017-11-11

4

1 回答 1

1

嗯,这有点尴尬,但这是我首先想到的。我确信它可以被清理干净。我必须做一个二级 CTE 才能让它在没有任何功能或任何东西的情况下工作。connect by使用or可能会更容易lag,但我猜您的软件工具也无法处理这些。

WITH cte(rate_name, cages, use_date) AS (
  SELECT 'I1',      8, DATE'2017-11-04' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-05' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-07' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-10' FROM DUAL UNION ALL
  SELECT 'I1',      7, DATE'2017-11-11' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-12' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-13' FROM DUAL UNION ALL
  SELECT 'I1',      8, DATE'2017-11-14' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-01' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-02' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-03' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-04' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-05' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-06' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-07' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 1, DATE'2017-11-08' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-09' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-10' FROM DUAL UNION ALL
  SELECT 'I1 - BR', 5, DATE'2017-11-11' FROM DUAL
),
recur as (
  SELECT
    c1.use_date,
    c1.rate_name,
    c1.cages, 
    case when c3.rate_name is null then c1.use_date else null end as start_date,
    case when c2.rate_name is null then c1.use_date else null end as end_date
  FROM cte c1
  -- next day
  left join cte c2 on c2.rate_name = c1.rate_name and c2.use_date = c1.use_date +1 and c2.cages = c1.cages
  -- prev day
  left join cte c3 on c3.rate_name = c1.rate_name and c3.use_date = c1.use_date -1 and c3.cages = c1.cages
)
select rate_name, cages, start_date, 
    (select min(e.end_date) from recur e
        where e.rate_name = s.rate_name
          and e.end_date >= s.start_date) as end_date
from recur s
where start_date is not null
order by rate_name, start_date;
于 2018-04-19T15:30:55.020 回答