sqlfiddle创建模式:

我想用Oracle中的模式查询一个层次 struct 表.模式和示例数据如下:

CREATE TABLE mappings 
(
    from_name varchar(20),
    to_name varchar(20),
    start_date date
);

INSERT INTO mappings VALUES ('node 1', 'node 1-2', date'2023-1-1');
INSERT INTO mappings VALUES ('node 1-2', 'node 1-3', date'2023-2-1');
INSERT INTO mappings VALUES ('node 1-3', 'Final Node 1', date'2023-3-1');
INSERT INTO mappings VALUES ('node 2', 'Final Node 2', date'2023-1-15');
INSERT INTO mappings VALUES ('node 3', 'Node 3-1', date'2023-2-1');
INSERT INTO mappings VALUES ('node 3-1', 'Final Node 1', date'2023-2-15');

该数据表示具有时间段的3种不同映射路径:

  • 路径1: node 1-> node 1-2-> node 1-3->最终 node 1
  • 路径2: node 2->最终 node 2
  • 路径3: node 3-> node 3-1->最终 node 1

请注意,路径1和路径3在末尾合并

我想要生成的输出是:

From To Start_Date End_Date
node 1 Final Node 1 2023-1-1 2023-1-31
node 1-2 Final Node 1 2023-2-1 2023-2-28
node 1-3 Final Node 1 2023-3-1
node 2 Final Node 2 2023-1-15
node 3-1 Final Node 1 2023-2-1 2023-2-14
node 3-2 Final Node 1 2023-2-15

我在Oracle中的代码:

WITH map AS 
(
    SELECT 
       connect_by_root(from_name) AS begin_node,
       (to_name) AS end_node,
       connect_by_root(start_date) AS start_date,
       LEVEL
   FROM 
       mappings
   WHERE 
       connect_by_isleaf = 1 
   CONNECT BY nocycle from_name = PRIOR to_name
)
SELECT 
    m.begin_node,
    m.end_node,
    start_date,
    LEAD(start_date - 1, 1) OVER (PARTITION BY end_node ORDER BY start_date) AS end_date
FROM 
    map m

上面的代码似乎在大多数情况下都可以工作,但在某些情况下end_date不正确.它从另一条路径拾取错误的结束日期,因为路径1和路径3在末尾合并.

推荐答案

在反方向上生成映射,首先找到根 node ,然后生成到叶子的映射,当你想找到end_date时,你可以PARTITION BY根 node (而不是结束 node ):

WITH reverse_map (from_name, to_name, start_date, root_name) AS (
  SELECT CONNECT_BY_ROOT from_name,
         CONNECT_BY_ROOT to_name,
         CONNECT_BY_ROOT start_date,
         from_name
  FROM   mappings
  WHERE  CONNECT_BY_ISLEAF = 1 
  CONNECT BY NOCYCLE
         PRIOR from_name = to_name
)
SELECT CONNECT_BY_ROOT from_name AS begin_node,
       to_name AS end_node,
       CONNECT_BY_ROOT start_date AS start_date,
       LEAD(CONNECT_BY_ROOT start_date) OVER (
         PARTITION BY CONNECT_BY_ROOT root_name
         ORDER BY CONNECT_BY_ROOT start_date
       ) - INTERVAL '1' SECOND AS end_date
FROM   reverse_map
WHERE  CONNECT_BY_ISLEAF = 1 
CONNECT BY NOCYCLE
       from_name = PRIOR to_name

以下哪项输出:

BEGIN_NODE END_NODE START_DATE END_DATE
node 1 Final Node 1 2023-01-01 00:00:00 2023-01-31 23:59:59
node 1-2 Final Node 1 2023-02-01 00:00:00 2023-02-28 23:59:59
node 1-3 Final Node 1 2023-03-01 00:00:00 null
node 2 Final Node 2 2023-01-15 00:00:00 null
node 3 Final Node 1 2023-02-01 00:00:00 2023-02-14 23:59:59
node 3-1 Final Node 1 2023-02-15 00:00:00 null

fiddle

Sql相关问答推荐

Postgresql在加入时显示重复的行

Oracle SQL中的累计总数

从字符串中删除";1、";和";2,";,而不删除";11、";和";12、";

NULL-生成的列中连接的字符串的输入

从列中提取子字符串的ORDER BY CASE语句

为什么我的SQL标量函数有时会抛出";子查询返回多个值.这是不允许的.

带上最后日期(结果)

将FLOAT转换为VARBINARY,然后再转换回FLOAT

SQL Athena/prest判断值是否在嵌套的json数组中

从选定记录中提取摘要作为值的划分

当 ansible 变量未定义或为空时,跳过 sql.j2 模板中的 DELETE FROM 查询

使用 SQL 将列添加到 Access 数据库时出错

从另一个没有公共键的表中获取值来加入

替换SQL Server XML中多处出现的 node 值

将最近的结束日期与开始日期相匹配

当我返回 sql 列时,有没有办法只反转数字? ( hebrew )

获取上个月和上一年的值

PostgreSQL - 递归地聚合来自不同列的属性

As400 (IBM i) SQL 表 QSYS2.SYSTABLES 上的元数据

查找具有相同连接列数据的所有记录