【问题标题】:find nearest row of different type in oracle在oracle中找到最近的不同类型的行
【发布时间】:2016-03-12 12:09:39
【问题描述】:

我的桌子看起来像

__   Key   type  timeStamp             flag
1 )    1     B    2015-06-28 22:19:26   Y
2 )    1     B    2015-06-28 22:20:22   Y
3 )    1     C    2015-06-28 22:22:06   N
4 )    1     A    2015-06-28 22:25:11   N
5 )    1     B    2015-06-28 22:29:44   Y
6 )    1     A    2015-06-28 22:33:33   N
7 )    1     B    2015-06-28 22:35:21   N
8 )    1     B    2015-06-28 22:39:34   Y
9 )    1     B    2015-06-28 22:43:53   N
10)    1     A    2015-06-28 22:45:53   N

我需要找出所有类型 A 的 flag='N' 相对于存在类型 B 的 timestampOF(B)<timestampOF(A)Flag(B)='Y'key(A)=key(B)

注意:如果在 A 之前存在两个 B,则取最大时间戳的 B。(取 ROW[8,9,10] 9 而不是 8)

输出

__   Key   type  timeStamp             flag
4 )    1     A    2015-06-28 22:25:11   N
6 )    1     A    2015-06-28 22:33:33   N

我的方法

SELECT  *
FROM    tab TAB_OUT
WHERE   TAB_OUT.TYPE='A'
    AND TAB_OUT.FLAG='N'
    AND EXISTS(
            SELECT   *
            FROM    tab TAB_IN
            WHERE   TAB_IN.KEY = TAB_OUT.KEY
                    AND     TAB_IN.TYPE='B'
                    AND     TAB_OUT.FLAG='Y'
                    AND     TAB_IN.timestamp<TAB_OUT.timestamp
                    AND     TAB_IN.timestamp = (SELECT MAX(timestamp) from       
 tab where timestamp< `TAB_OUT.timestamp`)
 );
  1. 但在此我不能在第三级查询中使用TAB_OUT.timestamp。有没有其他解决方案可以解决这个问题。

  2. 在我的查询 note: 中,部分不满足我的查询,因为它跳过了 no。 9) 并且满足条件没有。 8)

【问题讨论】:

  • 请不要将列命名为 timestamptypekey - 虽然它会起作用,但这些是 SQL 中的关键字,因此可能会造成混淆。
  • 如果您有一个 B, Y 行,后面紧跟两个具有相同键的 A, N 行,会发生什么情况 - 您希望只有第一个 A 行还是两者都有?

标签: oracle exists


【解决方案1】:

只需要一次表扫描的解决方案:

SQL Fiddle

Oracle 11g R2 架构设置

CREATE TABLE table_name ( Key, type, timeStamp, flag ) AS
          SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:19:26' AS DATE ), 'Y' FROM DUAL
UNION ALL SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:20:22' AS DATE ), 'Y' FROM DUAL
UNION ALL SELECT 1, 'C', CAST( TIMESTAMP '2015-06-28 22:22:06' AS DATE ), 'N' FROM DUAL
UNION ALL SELECT 1, 'A', CAST( TIMESTAMP '2015-06-28 22:25:11' AS DATE ), 'N' FROM DUAL
UNION ALL SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:29:44' AS DATE ), 'Y' FROM DUAL
UNION ALL SELECT 1, 'A', CAST( TIMESTAMP '2015-06-28 22:33:33' AS DATE ), 'N' FROM DUAL
UNION ALL SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:35:21' AS DATE ), 'N' FROM DUAL
UNION ALL SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:39:34' AS DATE ), 'Y' FROM DUAL
UNION ALL SELECT 1, 'B', CAST( TIMESTAMP '2015-06-28 22:43:53' AS DATE ), 'N' FROM DUAL
UNION ALL SELECT 1, 'A', CAST( TIMESTAMP '2015-06-28 22:45:53' AS DATE ), 'N' FROM DUAL

查询 1

SELECT  Key,
        type,
        timeStamp,
        flag
FROM (
  SELECT  Key,
          type,
          timeStamp,
          flag,
          LAG( CASE WHEN type = 'B' THEN flag END ) IGNORE NULLS OVER ( PARTITION BY Key ORDER BY timeStamp ) AS prev_b_flag
  FROM    table_name t
  WHERE   type IN ( 'A', 'B' )
)
WHERE   type        = 'A'
AND     flag        = 'N'
AND     prev_b_flag = 'Y'

Results

| KEY | TYPE |              TIMESTAMP | FLAG |
|-----|------|------------------------|------|
|   1 |    A | June, 28 2015 22:25:11 |    N |
|   1 |    A | June, 28 2015 22:33:33 |    N |

【讨论】:

  • 感谢您的回答。但你的代码给了我 3 行(预期 2 行)。 note 语句无效,因为 A 需要检查具有标志 Y 和最大时间戳但小于 A 的时间戳的 B
  • @Anonymous - 更新以反映您对 note 声明无效的说明。我更新的答案仍然只需要一次表扫描。
【解决方案2】:
SELECT
    *
FROM
    tab A
WHERE
    flag = 'N' AND type = 'A'
    AND EXISTS (
        SELECT
            NULL
        FROM
            tab B
        WHERE
            type = 'B'
            AND A.timestamp > timestamp AND A.Key = Key
        GROUP BY
            Key
        HAVING
            MAX(flag) KEEP (DENSE_RANK LAST ORDER BY timestamp) = 'Y'
    );

无需进行关联查询即可从最后一条记录中选择标志。使用聚合 KEEP 子句是更有效的方法。在这种情况下,它按时间戳对组进行排序并只保留聚合的最后一个值(您想要的最后一个时间戳),因此 MAX 函数只有一条记录,我们只需从中获取 FLAG 值。

这是一个简单的例子:

WITH sample (value1, value2) AS (
    SELECT 1, 'Y' FROM DUAL UNION ALL
    SELECT 2, 'X' FROM DUAL
)
SELECT
    MIN(value2) KEEP (DENSE_RANK LAST ORDER BY value1) value2
FROM
    sample

这会从最高 value1 的记录中返回 value2。

【讨论】:

    猜你喜欢
    • 2019-01-11
    • 1970-01-01
    • 2011-01-19
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 2021-05-06
    相关资源
    最近更新 更多