查询仅获取一个人的行

时间:2016-12-05 06:12:02

标签: sql oracle

我有一张表xx_wr:

PERSON_NUM      ACTION_CODE       EFF_START_DATE    EFF_END_DATE
10               RE                01-JAN-2016        31-DEC-4712
12               TERM              02-FEB-2016         01-MAR-2016
12                RE               02-MAR-2016        31-DEC-4712

理想情况下,当有人的RE动作代码时,也应该有一个TERM动作代码记录。例如:人数:12 我正在查询只将action_code作为RE获取所有人,并且没有针对相同人员编号的行动代码作为TERM。例如:10

SELECT *
FROM
  ( SELECT xx_WR.ACTION_CODE ACTION_CODE,
           ROW_NUMBER() over (partition BY PERSON_NUM
                              ORDER BY ACTION_CODE) AS rn
   FROM xx_WR ) T
WHERE RN =1
  AND ACTION_CODE='RE';

此查询返回12和10.它应该只选择10,因为我们在此表中将action_code作为“RE”并且没有“TERM”行获取这些人员编号。

1 个答案:

答案 0 :(得分:1)

SELECT *
FROM
    (
       SELECT
          *
          ,ROW_NUMBER() OVER (PARTITION BY PERSON_NUM, ACTION_CODE ORDER BY EFF_END_DATE DESC) as rn
          ,COUNT(CASE WHEN ACTION_CODE = 'RE' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as RECount
          ,COUNT(CASE WHEN ACTION_CODE = 'TERM' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as TERMCount
       FROM
          xx_WR
    ) t
WHERE
    t.rn = 1
    AND t.ACTION_CODE = 'RE'
    AND t.RECount > t.TERMCount

所以ROW_NUMBER()只做那个,它构建一个行号。实际上,您需要比较每RETERM条记录与PERSON_NUM条记录的数量。根据您的描述,听起来您可能会得到RE -> TERM -> RE之类的案例,然后您又想要返回该案例。无论如何,在这里使用窗口函数非常棒,尤其是当您与条件聚合合作时。另请注意,此解决方案将处理RE -> RE情况并仍返回最新的RE记录。

请注意,如果您只想查找没有任何条款记录的情况,您可以进行调整:

SELECT *
FROM
    (
       SELECT
          *
          ,ROW_NUMBER() OVER (PARTITION BY PERSON_NUM, ACTION_CODE ORDER BY EFF_END_DATE DESC) as rn
          ,COUNT(CASE WHEN ACTION_CODE = 'RE' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as RECount
          ,COUNT(CASE WHEN ACTION_CODE = 'TERM' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as TERMCount
       FROM
          xx_WR
    ) t
WHERE
    t.rn = 1
    AND t.ACTION_CODE = 'RE'
    AND t.TERMCount = 0

如果你只想要一个拥有1条RE记录且没有TERM的人你可以再次稍微更改where子句,或者你也不再需要行号,这样你就可以这样做:

SELECT *
FROM
    (
       SELECT
          *
          ,COUNT(CASE WHEN ACTION_CODE = 'RE' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as RECount
          ,COUNT(CASE WHEN ACTION_CODE = 'TERM' THEN 1 END) OVER (PARTITION BY PERSON_NUM) as TERMCount
       FROM
          xx_WR
    ) t
WHERE
    t.ACTION_CODE = 'RE'
    AND t.RECount = 1
    AND t.TERMCount = 0