在oracle中找到最近的不同类型的行

find nearest row of different type in oracle

我的table长得像

__   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' 相对于存在 timestampOF(B)<timestampOF(A)Flag(B)='Y'key(A)=key(B) 的类型 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: 部分不满意,因为我的查询跳过了编号。 9)并满足条件没有。 8)

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'
    );

不需要从最后一条记录到select标志做关联查询。使用聚合 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

这个 returns 值 2 来自具有最高值 1 的记录。

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

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 |