oraclesql中的日期和交叉连接

ymdaylpp  于 2021-07-29  发布在  Java
关注(0)|答案(3)|浏览(309)

我正在使用oraclesql,在使用交叉连接时遇到了一个问题。我有一个表,services,它有服务的开始和结束日期:

SRVC         START          END
Therapy      JAN-1-20       JAN-5-20
Baseball     FEB-15-20      FEB-18-20

我需要将此表转换为以下内容:

SRVC         DATE
Therapy      JAN-1-20
Therapy      JAN-2-20
...
Therapy      JAN-5-20
Baseball     FEB-15-20
Baseball     FEB-16-20
...
Baseball     FEB-18-20

基本上,我需要每天一行,而不是一个日期范围。我目前的做法如下。我还有一张table,日期\时间,上面有日期,例如。

CALDR_DT
JAN-1-20
...
DEC-31-20

我正在做以下工作

SELECT s."SRVC", d."CALDR_DT"
FROM SERVICES s
CROSS JOIN DATE_TIME d
WHERE d."CALDR_DT" >= s."START" AND d."CALDR_DT" <= s."END";

我遇到的问题是,这运行速度非常慢,因为实际上,我有一个更大的数据集。有没有一个更有效的方法来做这件事,我错过了?
谢谢!

4xrmg8kj

4xrmg8kj1#

你不需要使用 DATE_TIME 表和a JOIN ; 相反,您可以使用递归子查询分解子句(recursive) WITH 子句)生成行:

WITH dates ( srvc, "DATE", "END" ) AS (
  SELECT srvc,
         "START",
         "END"
  FROM   table_name
UNION ALL
  SELECT srvc,
         "DATE" + INTERVAL '1' DAY,
         "END"
  FROM   dates
  WHERE  "DATE" + INTERVAL '1' DAY <= "END"
)
SELECT srvc, "DATE"
FROM   dates
ORDER BY srvc, "DATE";

(作为旁白,不要使用 START , END 以及 DATE 因为它们是关键字,所以需要将它们括在双引号中,这使它们区分大小写,以便能够在查询中使用。)
因此,对于您的示例数据:

CREATE TABLE table_name ( SRVC, "START", "END" ) AS
SELECT 'Therapy',  DATE '2020-01-01', DATE '2020-01-05' FROM DUAL UNION ALL
SELECT 'Baseball', DATE '2020-02-15', DATE '2020-02-20' FROM DUAL

这将输出:

SRVC     | DATE     
:------- | :--------
Baseball | 15-FEB-20
Baseball | 16-FEB-20
Baseball | 17-FEB-20
Baseball | 18-FEB-20
Baseball | 19-FEB-20
Baseball | 20-FEB-20
Therapy  | 01-JAN-20
Therapy  | 02-JAN-20
Therapy  | 03-JAN-20
Therapy  | 04-JAN-20
Therapy  | 05-JAN-20

db<>在这里摆弄

92dk7w1h

92dk7w1h2#

不确定这是否有帮助,但当你有两个 CROSS JOIN 和一个 WHERE 子句中的条件使用两个表中的元素,您可以重写它以使用 INNER JOIN 相反。。。有时数据库可以推断出更好的执行计划。
同样,我无法预测这是否会对您的情况有所帮助,但当它确实有帮助时,改进通常集中在更好地使用索引,其中 CROSS JOIN 忽略用于筛选结果的有用索引,而是选择一个更好的索引来对结果进行排序,或者选择一个覆盖所有使用的字段的索引,因为假定表中的每个记录都将被使用。
说到索引,如果这没有帮助,那就是下一个要考虑的问题。但由于我们不知道你已经有了什么索引,我在这里提出的任何建议都将是一个黑暗的机会。

qcbq4gxm

qcbq4gxm3#

这里不需要单独的日历表。相反,使用 CONNECT BY LEVEL :

SELECT DISTINCT SRVC, START_DATE + (LEVEL-1) AS SRVC_DATE
  FROM SERVICES
  CONNECT BY LEVEL <= (END_DATE - START_DATE)+1
  ORDER BY 1, 2

给定您提供的测试数据,这将生成结果

SRVC        SRVC_DATE
Baseball    15-FEB-20
Baseball    16-FEB-20
Baseball    17-FEB-20
Baseball    18-FEB-20
Therapy     01-JAN-20
Therapy     02-JAN-20
Therapy     03-JAN-20
Therapy     04-JAN-20
Therapy     05-JAN-20

db<>在这里摆弄

相关问题