oraclesql-密级

oraclesql-密级,sql,oracle,dense-rank,Sql,Oracle,Dense Rank,我有一个客户机数据表,其中选定的列如下所示: Row_ID Client_ID Status_ID From_date To_date 1 123456 4 20/12/2007 18:02 20/12/2007 18:07 2 789087 4 20/12/2007 18:02 20/12/2007 18:07 3 789087 4 20/12

我有一个客户机数据表,其中选定的列如下所示:

Row_ID  Client_ID  Status_ID  From_date           To_date
  1     123456       4        20/12/2007 18:02    20/12/2007 18:07
  2     789087       4        20/12/2007 18:02    20/12/2007 18:07
  3     789087       4        20/12/2007 18:07    20/12/2007 18:50
  4     789087       4        20/12/2007 18:50    21/12/2007 10:38
  5     123456       4        20/12/2007 18:07    20/12/2007 18:50
  6     123456       4        20/12/2007 18:50    21/12/2007 10:38
  7     123456       4        21/12/2007 10:38    21/12/2007 16:39
  8     789087       4        21/12/2007 10:38    21/12/2007 17:54
  9     789087       4        21/12/2007 17:54    21/12/2007 18:32
 10     789087       4        21/12/2007 18:32    22/12/2007 06:48
 11     123456       5        21/12/2007 16:39
 12     789087       5        22/12/2007 06:48    22/12/2007 10:53
 13     789087       4        22/12/2007 10:53    22/12/2007 11:51
 14     789087       5        22/12/2007 11:51  
Row_ID  Client_ID  Status_ID  From_date           To_date            Rank_ID
  1     123456       4        20/12/2007 18:02    20/12/2007 18:07    1
  5     123456       4        20/12/2007 18:07    20/12/2007 18:50    1
  6     123456       4        20/12/2007 18:50    21/12/2007 10:38    1
  7     123456       4        21/12/2007 10:38    21/12/2007 16:39    1
 11     123456       5        21/12/2007 16:39                        2
  2     789087       4        20/12/2007 18:02    20/12/2007 18:07    3
  3     789087       4        20/12/2007 18:07    20/12/2007 18:50    3
  4     789087       4        20/12/2007 18:50    21/12/2007 10:38    3
  8     789087       4        21/12/2007 10:38    21/12/2007 17:54    3
  9     789087       4        21/12/2007 17:54    21/12/2007 18:32    3
 10     789087       4        21/12/2007 18:32    22/12/2007 06:48    3
 12     789087       5        22/12/2007 06:48    22/12/2007 10:53    4
 13     789087       4        22/12/2007 10:53    22/12/2007 11:51    5
 14     789087       5        22/12/2007 11:51                        6
在将数据按客户机ID和起始日期按升序排列之后,我的目标是在将状态与前一行进行比较时,每当该客户机的状态发生变化时,添加一个计算出的排名ID。我想要的Rank_ID的期望值如下所示:

Row_ID  Client_ID  Status_ID  From_date           To_date
  1     123456       4        20/12/2007 18:02    20/12/2007 18:07
  2     789087       4        20/12/2007 18:02    20/12/2007 18:07
  3     789087       4        20/12/2007 18:07    20/12/2007 18:50
  4     789087       4        20/12/2007 18:50    21/12/2007 10:38
  5     123456       4        20/12/2007 18:07    20/12/2007 18:50
  6     123456       4        20/12/2007 18:50    21/12/2007 10:38
  7     123456       4        21/12/2007 10:38    21/12/2007 16:39
  8     789087       4        21/12/2007 10:38    21/12/2007 17:54
  9     789087       4        21/12/2007 17:54    21/12/2007 18:32
 10     789087       4        21/12/2007 18:32    22/12/2007 06:48
 11     123456       5        21/12/2007 16:39
 12     789087       5        22/12/2007 06:48    22/12/2007 10:53
 13     789087       4        22/12/2007 10:53    22/12/2007 11:51
 14     789087       5        22/12/2007 11:51  
Row_ID  Client_ID  Status_ID  From_date           To_date            Rank_ID
  1     123456       4        20/12/2007 18:02    20/12/2007 18:07    1
  5     123456       4        20/12/2007 18:07    20/12/2007 18:50    1
  6     123456       4        20/12/2007 18:50    21/12/2007 10:38    1
  7     123456       4        21/12/2007 10:38    21/12/2007 16:39    1
 11     123456       5        21/12/2007 16:39                        2
  2     789087       4        20/12/2007 18:02    20/12/2007 18:07    3
  3     789087       4        20/12/2007 18:07    20/12/2007 18:50    3
  4     789087       4        20/12/2007 18:50    21/12/2007 10:38    3
  8     789087       4        21/12/2007 10:38    21/12/2007 17:54    3
  9     789087       4        21/12/2007 17:54    21/12/2007 18:32    3
 10     789087       4        21/12/2007 18:32    22/12/2007 06:48    3
 12     789087       5        22/12/2007 06:48    22/12/2007 10:53    4
 13     789087       4        22/12/2007 10:53    22/12/2007 11:51    5
 14     789087       5        22/12/2007 11:51                        6
我试图使用稠密的_秩作为分析函数,下面是我的“不正确”SQL代码

SELECT t1.*, DENSE_RANK () OVER (ORDER BY t1.client_id, t1.status_id) rank_id
FROM (SELECT c.client_ID, c.status_id, c.from_date, c.to_date
      FROM client c
      ORDER BY c.client_id, c.from_date) t1
ORDER BY t1.client_id, t1.from_date
但是,我遇到的问题是,给定编写的SQL代码,它会按如下方式计算秩_ID:

Row_ID  Client_ID  Status_ID  From_date           To_date            Rank_ID
  1     123456       4        20/12/2007 18:02    20/12/2007 18:07    1
  5     123456       4        20/12/2007 18:07    20/12/2007 18:50    1
  6     123456       4        20/12/2007 18:50    21/12/2007 10:38    1
  7     123456       4        21/12/2007 10:38    21/12/2007 16:39    1
 11     123456       5        21/12/2007 16:39                        2
  2     789087       4        20/12/2007 18:02    20/12/2007 18:07    3
  3     789087       4        20/12/2007 18:07    20/12/2007 18:50    3
  4     789087       4        20/12/2007 18:50    21/12/2007 10:38    3
  8     789087       4        21/12/2007 10:38    21/12/2007 17:54    3
  9     789087       4        21/12/2007 17:54    21/12/2007 18:32    3
 10     789087       4        21/12/2007 18:32    22/12/2007 06:48    3
 12     789087       5        22/12/2007 06:48    22/12/2007 10:53    4
 13     789087       4        22/12/2007 10:53    22/12/2007 11:51    3
 14     789087       5        22/12/2007 11:51                        4
对于记录13,返回的秩_ID为3(而我想要5,当与该客户机上一条记录上的状态相比时,它是该客户机状态的变化),对于记录14,返回的秩_ID为4,而我想要6,因为与上一行相比,它也是该客户机状态的变化

我猜问题在于我的SQL按客户机ID然后按状态ID对数据排序,因此我可以理解为什么它会生成它给出的答案。问题是,无论我对稠密秩行做了什么更改,我都无法获得我想要的答案


任何帮助都将不胜感激。

据我所知,这是您所需要的:

select client_ID, status_id, from_date, to_date, 
       sum(start_of_group) over (order by client_ID, from_date) + 1 rank
  from (SELECT c.client_ID, c.status_id, c.from_date, c.to_date,
               case when lag(c.client_ID, 1, c.client_ID) over (order by c.client_ID, c.from_date) = c.client_ID 
                     and lag(c.status_id, 1, c.status_id) over (order by c.client_ID, c.from_date) = c.status_id
                    then 0 else 1 end start_of_group
          FROM client c)
 order by client_ID, from_date

问题是,你需要根据地位的变化而不是地位的价值来划分排名。我在输出中留下了一些额外的列,以便您可以看到它是如何派生的:

WITH dat as (
 SELECT 1 row_id,     123456 client_id,      4 status,       to_date('20/12/2007 18:02','dd/mm/yyyy hh24:mi') frdate,    to_date('20/12/2007 18:07','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   2 row_id,     789087  client_id,       4 status,        to_date('20/12/2007 18:02','dd/mm/yyyy hh24:mi') frdate,    to_date('20/12/2007 18:07','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   3 row_id,     789087 client_id,        4  status,       to_date('20/12/2007 18:07','dd/mm/yyyy hh24:mi') frdate,    to_date('20/12/2007 18:50','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   4 row_id,     789087 client_id,        4 status,        to_date('20/12/2007 18:50','dd/mm/yyyy hh24:mi') frdate,    to_date('21/12/2007 10:38','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   5  row_id,    123456 client_id,        4 status,        to_date('20/12/2007 18:07','dd/mm/yyyy hh24:mi') frdate,    to_date('20/12/2007 18:50','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   6 row_id,     123456 client_id,        4 status,        to_date('20/12/2007 18:50','dd/mm/yyyy hh24:mi') frdate,    to_date('21/12/2007 10:38','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   7  row_id,    123456 client_id,        4 status,        to_date('21/12/2007 10:38','dd/mm/yyyy hh24:mi') frdate,    to_date('21/12/2007 16:39','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   8 row_id,     789087  client_id,       4  status,       to_date('21/12/2007 10:38','dd/mm/yyyy hh24:mi') frdate,    to_date('21/12/2007 17:54','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT   9 row_id,     789087  client_id,       4 status,        to_date('21/12/2007 17:54','dd/mm/yyyy hh24:mi') frdate,    to_date('21/12/2007 18:32','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT  10 row_id,     789087 client_id,        4 status,        to_date('21/12/2007 18:32','dd/mm/yyyy hh24:mi') frdate,    to_date('22/12/2007 06:48','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT  11 row_id,     123456  client_id,       5 status,        to_date('21/12/2007 16:39','dd/mm/yyyy hh24:mi') frdate,    null from dual union all
 SELECT  12 row_id,     789087 client_id,        5 status,        to_date('22/12/2007 06:48','dd/mm/yyyy hh24:mi') frdate,    to_date('22/12/2007 10:53','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT  13 row_id,     789087 client_id,        4  status,       to_date('22/12/2007 10:53','dd/mm/yyyy hh24:mi') frdate,    to_date('22/12/2007 11:51','dd/mm/yyyy hh24:mi') todate from dual union all
 SELECT  14 row_id,     789087 client_id,        5 status,        to_date('22/12/2007 11:51','dd/mm/yyyy hh24:mi') frdate,    null from dual)
SELECT t1.*, DENSE_RANK () OVER (ORDER BY t1.client_id, t1.chg_status) rank_id
FROM (select client_id, status, prev_status, sum(case when nvl(prev_status,-1) != status then 1 else 0 end) over (partition by client_id order by frdate) chg_status, frdate, todate
      from (
      SELECT c.client_ID
           , c.status
           , lag(status) over (partition by client_id order by frdate) as prev_status
           , c.frdate
           , c.todate
      FROM dat c
      ORDER BY c.client_id, c.frdate)) t1
ORDER BY t1.client_id, t1.frdate
返回:

CLIENT_ID, STATUS, PREV_STATUS, CHG_STATUS,  FRDATE,                 TODATE,              RANK_ID
123456,    4,      ,            1,           20/12/2007 6:02:00 PM, 20/12/2007 6:07:00 PM, 1
123456,    4,      4,            1,          20/12/2007 6:07:00 PM, 20/12/2007 6:50:00 PM, 1
123456,    4,      4,            1,          20/12/2007 6:50:00 PM, 21/12/2007 10:38:00 AM, 1
123456,    4,      4,            1,          21/12/2007 10:38:00 AM, 21/12/2007 4:39:00 PM, 1
123456,    5,      4,            2,          21/12/2007 4:39:00 PM,,                       2
789087,    4,      ,            1,           20/12/2007 6:02:00 PM,20/12/2007 6:07:00 PM, 3
789087,    4,      4,            1,          20/12/2007 6:07:00 PM,20/12/2007 6:50:00 PM, 3
789087,    4,      4,            1,          20/12/2007 6:50:00 PM, 21/12/2007 10:38:00 AM, 3
789087,    4,      4,            1,          21/12/2007 10:38:00 AM, 21/12/2007 5:54:00 PM, 3
789087,    4,      4,            1,          21/12/2007 5:54:00 PM, 21/12/2007 6:32:00 PM, 3
789087,    4,      4,            1,          21/12/2007 6:32:00 PM,22/12/2007 6:48:00 AM, 3
789087,    5,      4,            2,          22/12/2007 6:48:00 AM, 22/12/2007 10:53:00 AM, 4
789087,    4,      5,            3,          22/12/2007 10:53:00 AM, 22/12/2007 11:51:00 AM, 5
789087,    5,      4,            4,          22/12/2007 11:51:00 AM,,                      6

使用
1
(下面的GRP列)简单地标记每个客户端的所有状态更改。 然后使用解析求和函数将这些数字相加:

with tab1 as (
select client_id,from_date, status,
 nvl(lag(status) over (partition by client_id  order by from_date),-1) status_lag,
 case when (nvl(lag(status) over (partition by client_id  order by from_date),-1) <> status) then 
 1 end grp
from tst
)
, tab2 as (
select client_id,from_date, status,status_lag, grp,
sum(grp) over (partition by client_id  order by from_date) as RANK
from tab1
)
select * from tab2;
我的设置

 create table tst 
 (client_id number,
 from_date date,
 status number);

 insert into tst values (1001, to_date('01-10-15','dd-mm-rr'),1);
 insert into tst values (1001, to_date('02-10-15','dd-mm-rr'),1);
 insert into tst values (1001, to_date('03-10-15','dd-mm-rr'),2);
 insert into tst values (1001, to_date('04-10-15','dd-mm-rr'),2);
 insert into tst values (1001, to_date('05-10-15','dd-mm-rr'),3);
 insert into tst values (1001, to_date('09-10-15','dd-mm-rr'),1);
 insert into tst values (1002, to_date('12-10-15','dd-mm-rr'),1);
 insert into tst values (1002, to_date('13-10-15','dd-mm-rr'),3); 
 insert into tst values (1002, to_date('15-10-15','dd-mm-rr'),3);
 commit;
下面是一个使用以下方法的解决方案:


我应该补充一点,我对Oracle SQL比较陌生,当然,客户机表和其他列中有数百万行。我刚刚展示了一个小片段,您可以准备带有数据的测试表吗?它可以帮助人们测试您的问题的解决方案。谢谢Dmitry-我认为这是我需要和更喜欢的解决方案。的确很聪明