【问题标题】:Oracle SQL loop LEAD() through partitionOracle SQL 循环 LEAD() 通过分区
【发布时间】:2018-04-17 01:18:16
【问题描述】:

我有一个看起来像这样的集合

ID  date_IN  date_out
1    1/1/18   1/2/18
1    1/3/18   1/4/18
1    1/5/18   1/8/18
2    1/1/18   1/5/18
2    1/7/18   1/9/18

我从

开始
SELECT ID, date_IN, Date_out, lead(date_out) over ( partition by (ID)
order by ID) as next_out
From table

然后得到这样的东西......

ID  date_IN  date_out  next_out
1    1/1/18   1/2/18   1/4/18
1    1/3/18   1/4/18   1/8/18
1    1/5/18   1/8/18    Null
2    1/1/18   1/5/18    1/9/18
2    1/7/18   1/9/18   Null

我将遇到的问题是,在我的实际数据中,许多 ID 都有很多条目。目标是让所有的 date_out 出现在每个 ID 的一行中......

ID  date_IN  date_out  next_out  next_out1  etc.   etc.
1    1/1/18   1/2/18   1/4/18     1/8/18     X      X
2    1/1/18   1/5/18   1/7/18     X         Null    Null

有没有办法让lead() 循环遍历整个分区,按ID 顺序删除除第一行以外的所有内容,然后移至下一个ID?

【问题讨论】:

  • SQL 查询需要在结果集中有一组特定的列。 etc. 不是列的有效表示,因此我认为您无法使用基本的 SELECT 查询来做您想做的事情。
  • @a.s.1 - 您需要 PL/SQL 或动态 SQL,因为您需要知道执行多少次 LEAD() - lead(date_out, 1)...lead(date_out, 2)....等等。

标签: sql oracle loops lead


【解决方案1】:

这是一种方法,它假设您只希望每个ID 最多有三个日期对。你可以分配一个行号,然后通过ID聚合:

WITH cte AS (
    SELECT ID, date_IN, date_out,
        ROW_NUMBER() OVER (PARTITION BY ID ORDER BY date_IN) rn
    FROM yourTable
)

SELECT
    ID,
    MAX(CASE WHEN rn = 1 THEN date_IN END) AS date_IN,
    MAX(CASE WHEN rn = 1 THEN date_out END) AS date_out,
    MAX(CASE WHEN rn = 2 THEN next_IN END) AS next_in_1,
    MAX(CASE WHEN rn = 2 THEN date_out END) AS next_out_2,
    MAX(CASE WHEN rn = 3 THEN date_IN END) AS next_in_2,
    MAX(CASE WHEN rn = 3 THEN date_out END) AS next_out_2
FROM cte
GROUP BY ID

【讨论】:

    【解决方案2】:

    无需循环,但使用偏移选项。以下摘自文档。

    offset
    Optional. It is the physical offset from the current row in the table.
    If this parameter is omitted, the default is 1.
    
    example; lead(date_out) means next value
    lead(date_out, 2) means 2nd row after current row
    lead(date_out, 3) 3rd row after current row and so on.
    

    在您的代码中;在sn-p下面使用;

    lead(date_out) over ( partition by (ID) order by ID) as next_out,
    lead(date_out, 2) over ( partition by (ID) order by ID) as next_out2,
    lead(date_out, 3) over ( partition by (ID) order by ID) as next_out3
    

    【讨论】:

    • 这有一个潜在的问题,如果你硬编码像LEAD(date_out, 2)这样的东西,你可能会从另一个ID值中获取数据,如果当前ID没有预期的行数。
    • 我应该把整个代码贴出来的,因为和他写的一样,我没有放过分区顺序。要回答您的评论,如果当前行没有第三行,它将具有空值,并且不会从不同的 id 中获取其他日期。
    • 我想过,但有些 ID 有多达 200 个条目。你的回答意味着我必须每行做一个偏移量。这就是为什么我对某种循环感到好奇。我应该指出一些分区中有多少,抱歉。
    • 如果是这种情况,那么您需要一个过程,然后将数据插入另一个表,然后对该表进行选择。在这个过程中,你可以做一个 FOR LOOP
    • 将下一个输出列转置到 ID 上会更容易吗?
    【解决方案3】:
       WITH TAB AS(
    SELECT 1 ID,  CAST('2018/01/01' AS DATE) DATE_IN, CAST('2018/01/02' AS DATE) DATE_OUT FROM DUAL
    UNION
    SELECT 1, CAST('2018/01/03' AS DATE)   , CAST('2018/01/04' AS DATE) FROM DUAL
    UNION
    SELECT 1, CAST('2018/01/05' AS DATE)   , CAST('2018/01/08' AS DATE) FROM DUAL
    UNION
    SELECT 1, CAST('2018/01/09' AS DATE)   , CAST('2018/01/10' AS DATE) FROM DUAL
    UNION
    SELECT 1, CAST('2018/01/11' AS DATE)   , CAST('2018/01/12' AS DATE) FROM DUAL
    UNION
    SELECT 2, CAST('2018/01/01' AS DATE)   , CAST('2018/01/05' AS DATE) FROM DUAL
    UNION
    SELECT 2, CAST('2018/01/07' AS DATE)   , CAST('2018/01/09' AS DATE) FROM DUAL
    ) --select * from tab;
    , LEAF_CALC AS(   --CONNECTING THE DATE_OUTS
    SELECT 
    ID
    ,SYS_CONNECT_BY_PATH(DATE_OUT, '$') HRCHY
    , LEVEL LVL
    , CONNECT_BY_ISLEAF ISLEAF
    FROM TAB
    CONNECT BY PRIOR DATE_OUT < DATE_IN 
    START WITH ID = 1
    ) --SELECT * FROM LEAF_CALC;
    , DATA_SORT AS( --ADDING ALL DATE_OUTS IN 1 ROW
    SELECT
    P.ID, P.HRCHY
    FROM LEAF_CALC P,
    (SELECT ID, MAX(LVL) MAXLVL FROM
    LEAF_CALC
    GROUP BY ID) C
    WHERE P.ID = C.ID 
    AND P.LVL = C.MAXLVL
    )--SELECT * FROM DATA_SORT
    --SEGREGATING ALL DATES USING REGEXP_SUBSTR
    SELECT
    ID
    , REGEXP_SUBSTR(HRCHY, '[^$]+', 1, 1) DATE_IN
    , REGEXP_SUBSTR(HRCHY, '[^$]+', 1, 2) NEXT_OUT
    , REGEXP_SUBSTR(HRCHY, '[^$]+', 1, 3) NEXT_OUT2
    , COALESCE(REGEXP_SUBSTR(HRCHY, '[^$]+', 1, 4), 'NA') NEXT_OUT3
    , COALESCE(REGEXP_SUBSTR(HRCHY, '[^$]+', 1, 5), 'NA') NEXT_OUT4
    FROM DATA_SORT; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-02
      • 2013-08-31
      • 1970-01-01
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      相关资源
      最近更新 更多