奇怪的交织要求

时间:2019-05-10 17:49:49

标签: sql oracle

我有一个包含(简单),用户,操作,日期的日志表。 有两种操作:搜索和查看(搜索可能返回一百条记录;用户可以查看零个或更多)。

我需要按日期对基本输出进行排序,但是我也需要将所有视图一起用于一次搜索。像

 name    operation     date
 john    search        1/1 1pm
 john    view          1/1 2pm
 john    view          1/1 3pm
 james   search        1/1 230pm
 james   view          1/1 315pm
 john    search        1/1 310pm

似乎我需要使用子查询的结果来执行查询,但是我不确定它的外观。我对SQL没问题,但我对JOIN和UNION有点失望。 :-/

2 个答案:

答案 0 :(得分:1)

您可以使用窗口功能来识别组。而且您可以在order by中包括窗口函数,因此不需要子查询。

select *
from log_table l
order by max(case when l.operation = 'search' then l.log_date end) over (partition by l.name order by l.log_date),
         l.name,
         l.log_date;

Here是db <>小提琴。

答案 1 :(得分:0)

您可以使用条件lag()调用来查找每个用户每个视图行的最新搜索日期/时间;搜索行获得自己的日期/时间:

-- CTE for sample data
with log_table (name, operation, log_date) as (
            select 'john', 'search', timestamp '2019-01-01 13:00:00' from dual
  union all select 'john', 'view', timestamp '2019-01-01 14:00:00' from dual
  union all select 'john', 'view', timestamp '2019-01-01 15:00:00' from dual
  union all select 'james', 'search', timestamp '2019-01-01 14:30:00' from dual
  union all select 'james', 'view', timestamp '2019-01-01 15:15:00' from dual
  union all select 'john', 'search', timestamp '2019-01-01 15:10:00' from dual
)
-- actual query
select name, operation, log_date,
  case when operation = 'search' then log_date
       else  lag(case when operation = 'search' then log_date end ignore nulls)
               over (partition by name order by log_date)
  end as search_date
from log_table
order by log_date;

NAME  OPERATION LOG_DATE            SEARCH_DATE        
----- --------- ------------------- -------------------
john  search    2019-01-01 13:00:00 2019-01-01 13:00:00
john  view      2019-01-01 14:00:00 2019-01-01 13:00:00
james search    2019-01-01 14:30:00 2019-01-01 14:30:00
john  view      2019-01-01 15:00:00 2019-01-01 13:00:00
john  search    2019-01-01 15:10:00 2019-01-01 15:10:00
james view      2019-01-01 15:15:00 2019-01-01 14:30:00

然后可以将其用作CTE或内联视图,并使用生成的search_date进行排序,然后按实际记录日期对具有相同搜索日期的记录进行排序:

-- CTE for sample data
with log_table (name, operation, log_date) as (
            select 'john', 'search', timestamp '2019-01-01 13:00:00' from dual
  union all select 'john', 'view', timestamp '2019-01-01 14:00:00' from dual
  union all select 'john', 'view', timestamp '2019-01-01 15:00:00' from dual
  union all select 'james', 'search', timestamp '2019-01-01 14:30:00' from dual
  union all select 'james', 'view', timestamp '2019-01-01 15:15:00' from dual
  union all select 'john', 'search', timestamp '2019-01-01 15:10:00' from dual
)
-- actual query
select name, operation, log_date
from (
  select name, operation, log_date,
    case when operation = 'search' then log_date
         else  lag(case when operation = 'search' then log_date end ignore nulls)
                 over (partition by name order by log_date)
    end as search_date
  from log_table
)
order by search_date, log_date;

NAME  OPERATION LOG_DATE           
----- --------- -------------------
john  search    2019-01-01 13:00:00
john  view      2019-01-01 14:00:00
john  view      2019-01-01 15:00:00
james search    2019-01-01 14:30:00
james view      2019-01-01 15:15:00
john  search    2019-01-01 15:10:00

由于您可能会同时获得两个用户的搜索,因此您可能也希望将该用户包括在最终的order-by子句中:

...
order by search_date, name, log_date;