Oracle:当一列中的值更改时 Select 行
Oracle: Select rows when value in one column changes
我有以下 table:
PLACE USER_ID Date
---------- ---------- -----------------------------
ABC 4 14/04/20 12:05:29,255000000
ABC 4 14/04/20 15:42:28,389000000
ABC 4 14/04/20 18:33:20,202000000
ABC 4 14/04/20 22:51:28,339000000
XYZ 4 14/04/20 11:07:23,335000000
XYZ 2 14/04/20 12:15:12,123000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
XYZ 2 14/04/20 10:05:47,255000000
而且我需要获取当地点按日期更改顺序时我 select 的 user_id 的行。
所以期望的结果应该是这样的(对于 user_id 4):
PLACE USER_ID DATE
---------- ---------- -----------------------------
ABC 4 14/04/20 12:05:29,255000000
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
我尝试使用最短日期,但在我的示例中,如果用户回到那个地方,我会丢失数据:
SELECT MIN(DATE), PLACE FROM user_places WHERE USER_ID=4 GROUP BY PLACE
我得到的结果(缺少一行):
PLACE USER_ID DATE
---------- ---------- -----------------------------
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
提前致谢!
您可以在子查询中使用 lag()
来检索 "previous" 位置,然后过滤前一个位置与当前位置不同的行:
select place, user_id, date
from (
select t.*, lag(place) over(partition by user_id order by date) lag_place
from mytable t
) t
where lag_place is null or place <> lag_place
这为您提供了所有用户的预期输出。如果你只想要用户 4,那么你可以在子查询中过滤(并且不需要 partition by
用户):
select place, user_id, date
from (
select t.*, lag(place) over(order by date) lag_place
from mytable t
where user_id = 4
) t
where lag_place is null or place <> lag_place
在 Oracle 12.1 及更高版本中,像这样的间隙和孤岛问题对于 match_recognize
子句来说是一项简单的任务。例如:
Table设置
alter session set nls_timestamp_format = 'dd/mm/rr hh24:mi:ss,ff';
create table user_places (place, user_id, date_) as
select 'ABC', 4, to_timestamp('14/04/20 12:05:29,255000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 15:42:28,389000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 18:33:20,202000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 22:51:28,339000000') from dual union all
select 'XYZ', 4, to_timestamp('14/04/20 11:07:23,335000000') from dual union all
select 'XYZ', 2, to_timestamp('14/04/20 12:15:12,123000000') from dual union all
select 'ABC', 4, to_timestamp('13/04/20 22:09:33,255000000') from dual union all
select 'QWE', 4, to_timestamp('13/04/20 10:18:29,144000000') from dual union all
select 'XYZ', 2, to_timestamp('14/04/20 10:05:47,255000000') from dual
;
commit;
查询输出
select place, user_id, date_
from (select * from user_places where user_id = 4)
match_recognize (
order by date_
all rows per match
pattern (a {- b* -} )
define b as place = a.place
)
order by date_ desc -- if needed
;
PLACE USER_ID DATE_
----- ------- ---------------------------
ABC 4 14/04/20 12:05:29,255000000
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
这里有几点需要注意:
DATE
是保留关键字。不是一个好的列名。我用了 DATE_
反而;注意结尾的下划线。
- 我硬编码了值 4。当然,更好的做法是把它变成一个绑定变量。
- 如果您真的一次只需要为一个
user_id
执行此操作,那么执行我所做的最有效 - 首先在子查询中过滤行。但是,如果您需要对同一查询中的所有用户 ID 执行此操作,则不需要子查询;你 select 来自 table 本身,你需要在 match_recognize
子句的顶部添加 partition by user_id
,在 order by date_
. 之前
我有以下 table:
PLACE USER_ID Date
---------- ---------- -----------------------------
ABC 4 14/04/20 12:05:29,255000000
ABC 4 14/04/20 15:42:28,389000000
ABC 4 14/04/20 18:33:20,202000000
ABC 4 14/04/20 22:51:28,339000000
XYZ 4 14/04/20 11:07:23,335000000
XYZ 2 14/04/20 12:15:12,123000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
XYZ 2 14/04/20 10:05:47,255000000
而且我需要获取当地点按日期更改顺序时我 select 的 user_id 的行。 所以期望的结果应该是这样的(对于 user_id 4):
PLACE USER_ID DATE
---------- ---------- -----------------------------
ABC 4 14/04/20 12:05:29,255000000
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
我尝试使用最短日期,但在我的示例中,如果用户回到那个地方,我会丢失数据:
SELECT MIN(DATE), PLACE FROM user_places WHERE USER_ID=4 GROUP BY PLACE
我得到的结果(缺少一行):
PLACE USER_ID DATE
---------- ---------- -----------------------------
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
提前致谢!
您可以在子查询中使用 lag()
来检索 "previous" 位置,然后过滤前一个位置与当前位置不同的行:
select place, user_id, date
from (
select t.*, lag(place) over(partition by user_id order by date) lag_place
from mytable t
) t
where lag_place is null or place <> lag_place
这为您提供了所有用户的预期输出。如果你只想要用户 4,那么你可以在子查询中过滤(并且不需要 partition by
用户):
select place, user_id, date
from (
select t.*, lag(place) over(order by date) lag_place
from mytable t
where user_id = 4
) t
where lag_place is null or place <> lag_place
在 Oracle 12.1 及更高版本中,像这样的间隙和孤岛问题对于 match_recognize
子句来说是一项简单的任务。例如:
Table设置
alter session set nls_timestamp_format = 'dd/mm/rr hh24:mi:ss,ff';
create table user_places (place, user_id, date_) as
select 'ABC', 4, to_timestamp('14/04/20 12:05:29,255000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 15:42:28,389000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 18:33:20,202000000') from dual union all
select 'ABC', 4, to_timestamp('14/04/20 22:51:28,339000000') from dual union all
select 'XYZ', 4, to_timestamp('14/04/20 11:07:23,335000000') from dual union all
select 'XYZ', 2, to_timestamp('14/04/20 12:15:12,123000000') from dual union all
select 'ABC', 4, to_timestamp('13/04/20 22:09:33,255000000') from dual union all
select 'QWE', 4, to_timestamp('13/04/20 10:18:29,144000000') from dual union all
select 'XYZ', 2, to_timestamp('14/04/20 10:05:47,255000000') from dual
;
commit;
查询输出
select place, user_id, date_
from (select * from user_places where user_id = 4)
match_recognize (
order by date_
all rows per match
pattern (a {- b* -} )
define b as place = a.place
)
order by date_ desc -- if needed
;
PLACE USER_ID DATE_
----- ------- ---------------------------
ABC 4 14/04/20 12:05:29,255000000
XYZ 4 14/04/20 11:07:23,335000000
ABC 4 13/04/20 22:09:33,255000000
QWE 4 13/04/20 10:18:29,144000000
这里有几点需要注意:
DATE
是保留关键字。不是一个好的列名。我用了DATE_
反而;注意结尾的下划线。- 我硬编码了值 4。当然,更好的做法是把它变成一个绑定变量。
- 如果您真的一次只需要为一个
user_id
执行此操作,那么执行我所做的最有效 - 首先在子查询中过滤行。但是,如果您需要对同一查询中的所有用户 ID 执行此操作,则不需要子查询;你 select 来自 table 本身,你需要在match_recognize
子句的顶部添加partition by user_id
,在order by date_
. 之前