如何根据Oracle中的列中的值区分整行?

时间:2017-03-13 09:31:34

标签: sql oracle greatest-n-per-group

示例数据有两个表:

Verify 1                                    Train 2
print_id     verifydate     score          print_id     traindate   segments
416         09-mar-17   99                 416           26-jul-16     2
522         09-mar-17   93                 522           26-jul-16     5
854         09-mar-17   88                 854           07-SEP-16     1
854         09-mar-17   91                 854           07-SEP-16     2
860         09-mar-17   85                 860           21-jul-16     1
864         09-mar-17   96                 864           06-SEP-16     3
864         09-mar-17   96                 864           10-SEP-16     4

print_id中的所有Verify都位于Train。我希望我的结果显示每次出现print_id' from验证with the respective verifydate and得分, and then for the same print_id to show its respective information from列车with the max(segments){{ 1}} traindate`。

and

但是,这是重复我的print_id的实际结果的示例,给出了以下结果:

SELECT DISTINCT Verify.PRINT_ID,
  MAX(Train.TOTAL_SEGMENTS) OVER (PARTITION BY Verify.PRINT_ID) AS segments,
  TRUNC(Train."TIMESTAMP")     AS traindate,     
  TRUNC(Verify."TIMESTAMP")     AS verifydate,
  Verify.Score
FROM Train INNER JOIN Verify ON Train.PRINT_ID  = Verify.PRINT_ID
WHERE TRUNC(Verify."TIMESTAMP") = '09-mar-2017' 
ORDER BY Verify.PRINT_ID 

正如您所注意到的,我的print_id segments date2 date1 score 416 2 26-JUL-16 09-MAR-17 99 522 5 26-JUL-16 09-MAR-17 93 854 2 07-SEP-16 09-MAR-17 88 854 2 07-SEP-16 09-MAR-17 91 860 1 21-JUL-17 09-MAR-17 85 864 4 06-SEP-16 09-MAR-17 96 864 4 10-SEP-16 09-MAR-17 96 部分每次都显示每个over(partition by ---),但每次显示最大段值。我如何简化这一点,以便我得到的结果相反:

verify.print_id

此外,由于工作限制,表名略有改变,但我希望这不应改变一般的想法。我也在使用Oracle SQL Developer上的3.0.04版。上面的查询运行没有任何问题,只是一些结果数据是不必要的。

以下建议的几个例子会产生错误: print_id segments traindate verifydate score
416 2 26-JUL-16 09-MAR-17 99 522 5 26-JUL-16 09-MAR-17 93 854 2 07-SEP-16 09-MAR-17 91 860 1 21-JUL-16 09-MAR-17 85 864 4 10-SEP-16 09-MAR-17 96
我已经检查并仔细检查了数据,逻辑,拼写,但无法弄清楚我做错了什么。 请注意我是SQL / Oracle以及本论坛的新手,因此我对所提供的任何信息缺乏表示诚挚的歉意。我曾尝试在这里查看其他示例,但努力让我对此有所了解。这甚至可能吗?

2 个答案:

答案 0 :(得分:0)

正如我在评论中提到的,我们没有表格和数据的全貌。但无论如何我会尽力提供答案。

逻辑如下:

首先在max中找到包含table2个细分的行(即t2),然后将结果行(t2)与table1结合起来。< / p>

with table2 as (
select 416  as print_id,    2 as  segments, sysdate as "TIMESTAMP" from dual 
union all
select 522  as print_id,   5 as  segments, sysdate as "TIMESTAMP" from dual
 union all
select 854  as print_id,   1 as  segments, sysdate as "TIMESTAMP" from dual
 union all
select 854  as print_id,   2 as  segments, sysdate as "TIMESTAMP" from dual
 union all
select 864  as print_id,   3 as  segments, sysdate as "TIMESTAMP" from dual
 union all
select 864  as print_id,   4 as  segments, sysdate as "TIMESTAMP" from dual
),
 table1 as (
select 416  as print_id,   99 as  score, sysdate as "TIMESTAMP" from dual 
union all
select 522  as print_id,   93 as  score, sysdate as "TIMESTAMP" from dual
 union all
select 854  as print_id,   88 as  score, sysdate-1 as "TIMESTAMP" from dual
 union all
select 854  as print_id,   91 as  score, sysdate-1 as "TIMESTAMP" from dual
 union all
select 864  as print_id,   96 as  score, sysdate-2 as "TIMESTAMP" from dual
 union all
select 864  as print_id,   96 as  score, sysdate-2 as "TIMESTAMP" from dual
),
t2 as 
(SELECT a.PRINT_ID , a.segments , a."TIMESTAMP"
FROM Table2 a
INNER JOIN (
    SELECT b.PRINT_ID , MAX(b.segments) segments
    FROM table2 b
    GROUP BY PRINT_ID
) b ON a.PRINT_ID  = b.PRINT_ID AND a.segments = b.segments
)
SELECT DISTINCT Table1.PRINT_ID,
  t2.segments,
  t2."TIMESTAMP",     
  TRUNC(Table1."TIMESTAMP")     AS date1,
  Table1.Score
FROM t2 INNER JOIN Table1 ON t2.PRINT_ID  = Table1.PRINT_ID
WHERE TRUNC(Table1."TIMESTAMP") = trunc(sysdate) 
ORDER BY Table1.PRINT_ID

答案 1 :(得分:0)

正如我在评论中所说,您没有提供生成您指定的结果集所需的所有业务规则。不幸的是,如果你无法解释你需要什么,我们无法给你答案,只有猜测。

所以,这是我的猜测:

  • table1选择print_id,最高分和相应的date1
  • 来自table2选择print_id,最大细分和相应的日期2

也就是说,结果集将根据得分和分段的最大值过滤日期列,而不是根据最新日期选择分数和分段。

因此,使用子查询因子分解语法和分析函数来实现我们得到的业务规则:

with t1 as (
     select print_id
            , score
            , trunc("TIMESTAMP") as date1
            , row_number() over (partition by print_id order by score desc) as rn
     from table1 )
, t2 as (
     select print_id
            , segments
            , trunc("TIMESTAMP") as date2
            , row_number() over (partition by print_id order by segments desc) as rn
     from table2 )
select t1.print_id
       , t2.segments
       , t1.date1
       , t2.date2
       , t1.score
from t1
     join t2
     on t1.print_id = t2.print_id 
        and t1.rn = t2.rn
where t1.rn = 1
order by t1.print_id