SQL Oracle - 将连续行与过滤器结合起来

Posted

技术标签:

【中文标题】SQL Oracle - 将连续行与过滤器结合起来【英文标题】:SQL Oracle - Combining consecutive rows with filter 【发布时间】:2015-06-20 19:33:49 【问题描述】:
| RecordId | foo_id | high_speed |   speed  | DateFrom   |  DateTo     |
------------------------------------------------------------------------
| 666542   |   12   |   60       |   10     | 09/11/2011 |  10/11/2011 |
| 666986   |   13   |   20       |   20     | 11/11/2011 |  11/11/2011 |
| 666996   |   12   |   0        |   0      | 13/11/2011 |  17/11/2011 |
| 755485   |   12   |   0        |   0      | 01/11/2011 |  14/11/2011 |
| 758545   |   12   |   70       |   50     | 15/11/2011 |  26/11/2011 |
| 796956   |   12   |   40       |   40     | 09/11/2011 |  09/11/2011 |
| 799656   |   13   |   25       |   20     | 09/11/2011 | 09/11/2011  |
| 808845   |   12   |   0        |   0      | 15/11/2011 | 15/11/2011  |
| 823323   |   12   |   0        |   0      | 15/11/2011 | 16/11/2011  |
| 823669   |   12   |   0        |   0      | 17/11/2011 | 18/11/2011  |
| 899555   |   12   |   0        |   0      | 18/11/2011 | 19/11/2011  |
| 990990   |   12   |   20       |   10     | 12/11/2011 | 12/11/2011  |

在这里,我想构建一个数据库视图,它结合了速度 = 0 的连续行。在这种情况下,DateFrom 将是第一行的 DateFrom 值,而 DateTo 将是最后一行的 DateTo 值。结果成表如下:

| foo_id | high_speed |    speed  | DateFrom    |    DateTo    |
---------------------------------------------------
|   12   |  60        |     10    |  09/11/2011 |  10/11/2011  |
|   13   |  20        |     20    |  11/11/2011 |  11/11/2011  |
|   12   |  0         |     0     |  13/11/2011 |  14/11/2011  |
|   12   |  70        |     50    |  15/11/2011 |  26/11/2011  |
|   12   |  40        |     40    |  09/11/2011 |  09/11/2011  |
|   13   |  25        |     20    |  09/11/2011 |  09/11/2011  |
|   12   |  0         |     0     |  15/11/2011 |  19/11/2011  |
|   12   |  20        |     10    |  12/11/2011 |  12/11/2011  |

为了获得结合速度为 0 的连续行的结果,我设计了用户 sql 查询的视图,如下所示:

select foo_id, high_speed, speed, datefrom, dateto, dateto-datefrom period
  from (
    select recordid, foo_id, high_speed, speed, datefrom, 
      case when tmp = 2 then lead(dateto) over (order by recordid) 
                        else dateto end dateto, tmp 
      from (
        select test.*, case when speed <> 0 then 1 
                       when lag(speed) over (order by recordid) <> 0 then 2
                       when lead(speed) over (order by recordid) <> 0 then 3 
                       end tmp
          from test )
      where tmp is not null)
   where tmp in (1, 2) order by recordid

现在,我必须应用与 foo_id 相同的结果。要获得此结果,需要将 foo_id 过滤器应用于内部嵌套查询。是否可以使用参数创建视图?或者我如何设计任何带有一个参数的函数,该参数将与 foo_id 列进行比较。前 -

select foo_id, high_speed, speed, datefrom, dateto, dateto-datefrom period
      from (
        select recordid, foo_id, high_speed, speed, datefrom, 
          case when tmp = 2 then lead(dateto) over (order by recordid) 
                            else dateto end dateto, tmp 
          from (
            select test.*, case when speed <> 0 then 1 
                           when lag(speed) over (order by recordid) <> 0 then 2
                           when lead(speed) over (order by recordid) <> 0 then 3 
                           end tmp
              from test where foo_id=12 )
          where tmp is not null)
       where tmp in (1, 2) order by recordid

【问题讨论】:

至于您的实际问题,您可能对这个答案感兴趣:***.com/questions/2059299/…。如果您想以正确的方式将0s 组合成一行(该词表示任意数量的0s),然后再问一个问题。 【参考方案1】:

问这个问题已经四年了。但是 Oracle 在 Oracle 12c 中添加了MATCH_RECOGNIZE 子句,这使得解决方案更加简单。

SELECT
  foo_id, high_speed, speed,
  NVL(DateFromZ, DateFrom) DateFrom,
  NVL(DateToZ, DateTo) DateTo
FROM test
MATCH_RECOGNIZE (
  ORDER BY RecordId
  MEASURES
    FIRST(zeros.DateFrom) AS DateFromZ,
    FINAL LAST(zeros.DateTo) AS DateToZ,
    COUNT(*) AS cnt
  ALL ROWS PER MATCH WITH UNMATCHED ROWS
  PATTERN (zeros+)
  DEFINE
    zeros AS zeros.speed = 0
)
WHERE speed > 0 OR cnt = 1
ORDER BY RecordId;

输出:

+--------+------------+-------+------------+------------+
| FOO_ID | HIGH_SPEED | SPEED |  DATEFROM  |   DATETO   |
+--------+------------+-------+------------+------------+
|     12 |         60 |    10 | 09/11/2011 | 10/11/2011 |
|     13 |         20 |    20 | 11/11/2011 | 11/11/2011 |
|     12 |          0 |     0 | 13/11/2011 | 14/11/2011 |
|     12 |         70 |    50 | 15/11/2011 | 26/11/2011 |
|     12 |         40 |    40 | 09/11/2011 | 09/11/2011 |
|     13 |         25 |    20 | 09/11/2011 | 09/11/2011 |
|     12 |          0 |     0 | 15/11/2011 | 19/11/2011 |
|     12 |         20 |    10 | 12/11/2011 | 12/11/2011 |
+--------+------------+-------+------------+------------+

db<>fiddle 上的演示。

【讨论】:

以上是关于SQL Oracle - 将连续行与过滤器结合起来的主要内容,如果未能解决你的问题,请参考以下文章

SQL ORACLE将两个表与htf(超文本函数)结合起来

Drupal 7 视图 - 如何将上下文过滤器与常规过滤器(使用 OR)结合起来?

Oracle Database-PL/SQL

SQL:将更新与分组结合起来?

Oracle SQL 中结合 LIMIT 子句访问主表字段的子查询

在 T-SQL 中将变量表与单个变量结合起来