SQL中的复杂RANK

时间:2015-02-24 19:25:41

标签: sql tsql

我有一个复杂的查询,这真的是我的头脑。 我认为需要RANK of the RANK-ing,但必须有更好的,现有的方式。

我在这里有一张简短的表格:

Manufacturer    DateOF  Status              Prefer
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerUninstalled 70
Dell            05-2014 ComputerUninstalled 70
Dell            05-2014 ComputerUninstalled 70
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerUninstalled 70
Dell            05-2014 ComputerNew         26
Dell            05-2014 ComputerNew         26
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerInstalled   30

我需要做的是通过MANUFACTURER和DATEOF列对表进行GROUP BY, 然后选择具有最低PREFER编号的行(在本例中为26)。

使用RANK函数很容易:

SELECT sq.*
FROM
(
SELECT
*,
RANK() OVER (PARTITION BY Manufacturer,DateOF ORDER BY Prefer) AS RankPrefer
FROM
table1
WHERE
RankPrefer = 1
) sq

所以我将使用Status ComputerNew获得2行的结果。

Manufacturer    DateOF  Status              Prefer
Dell            05-2014 ComputerNew         26
Dell            05-2014 ComputerNew         26

这很容易,而不是问题。

问题是:

我必须实施以下规则:

如果首选值最低的行(例如:26) 结果在状态字段中显示 ComputerNew 值, 然后我必须在 ComputerInstalled 值中包含更多行。

结果应该是这样的:

Manufacturer    DateOF  Status              Prefer
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerNew         26
Dell            05-2014 ComputerNew         26
Dell            05-2014 ComputerInstalled   30
Dell            05-2014 ComputerInstalled   30

与此规则类似,我还有一个:

如果首选值最低的行(例如:26) 结果在状态字段中显示 ComputerOld 值, 然后我必须在 ComputerUninstalled 值中包含更多行。

我认为RANK of RANKING会解决这个问题,但现在我真的迷失了。

在这个谜语中,任何帮助都会受到赞赏。

谢谢


EDIT1:

戈登的解决方案几乎是好的,但并不完美。

我给你更多测试数据,你可以看到它失败的地方。 要测试的SQLFiddle是here

我也在这里包含测试数据:

INSERT Table1 VALUES ('HP10011','04/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP10011','04/04/2014','ComputerOld',26)
INSERT Table1 VALUES ('HP10011','04/04/2014','ComputerOld',26)
INSERT Table1 VALUES ('HP10011','04/30/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP10011','05/23/2014','QuickDispose',10)
INSERT Table1 VALUES ('HP10011','06/03/2014','QuickDispose',10)
INSERT Table1 VALUES ('HP10077','04/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP1910','04/25/2014','QuickDispose',10)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP1910','05/01/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP1910','05/02/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP1910','05/02/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','05/07/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','05/08/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/08/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/08/2014','ComputerInstalled',30)
INSERT Table1 VALUES ('HP3720','05/08/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/06/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/06/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/10/2014','ComputerOld',26)
INSERT Table1 VALUES ('HP3720','06/10/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/10/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/11/2014','ComputerOld',26)
INSERT Table1 VALUES ('HP3720','06/11/2014','ComputerUninstalled',70)
INSERT Table1 VALUES ('HP3720','06/11/2014','ComputerUninstalled',70)

查询返回ComputerInstalled和ComputerUninstalled行 对于以下数据:

'HP1910','05/01/2014','ComputerInstalled',30
'HP1910','05/01/2014','ComputerUninstalled',70

它应该只选择ComputerInstalled,因为对于那个制造商,在同一个月,它应该选择最低的Prefer(30)。

此数据集的结果应为:

Manufacturer    DateOF  Status          Prefer
HP10011 2014-04-01  ComputerUninstalled 70
HP10011 2014-04-04  ComputerOld         26
HP10011 2014-04-04  ComputerOld         26
HP10011 2014-04-30  ComputerUninstalled 70
HP10011 2014-05-23  QuickDispose        10
HP10011 2014-06-03  QuickDispose        10
HP10077 2014-04-01  ComputerUninstalled 70
HP1910  2014-04-25  QuickDispose        10
HP1910  2014-05-01  ComputerInstalled   30
HP1910  2014-05-01  ComputerInstalled   30
HP1910  2014-05-01  ComputerInstalled   30
HP1910  2014-05-01  ComputerInstalled   30
HP3720  2014-05-07  ComputerInstalled   30
HP3720  2014-05-07  ComputerInstalled   30
HP3720  2014-05-08  ComputerInstalled   30
HP3720  2014-05-08  ComputerInstalled   30
HP3720  2014-05-08  ComputerInstalled   30
HP3720  2014-06-06  ComputerUninstalled 70
HP3720  2014-06-06  ComputerUninstalled 70
HP3720  2014-06-10  ComputerOld         26
HP3720  2014-06-10  ComputerUninstalled 70
HP3720  2014-06-10  ComputerUninstalled 70
HP3720  2014-06-11  ComputerOld         26
HP3720  2014-06-11  ComputerUninstalled 70
HP3720  2014-06-11  ComputerUninstalled 70

3 个答案:

答案 0 :(得分:3)

这是一个想法。找出行的首选项排名。然后使用exists确定rank = 1的行是否符合您的条件。

最终查询如下:

with r as (
      select t.*,
             rank() over (partition by manufacturer, dateof order by Prefer) as seqnum
      from table1 t
     ),
     r1 as (
      select r.*
      from r
      where seqnum = 1
     )
select r.*
from r
where r.seqnum = 1 or
      (exists (select 1 from r1 where status = 'ComputerNew' and r1.dateof = r.dateof) and r.status = 'ComputerInstalled' or
       exists (select 1 from r1 where status = 'ComputerOld' and r1.dateof = r.dateof) and r.status = 'ComputerUninstalled'
      );

答案 1 :(得分:2)

好的,既然你已经对这个问题做了一些修改,我有一个不同的答案,我认为这个问题会解决。这是查询:

;with r as (
      select t.*,
             CAST(MONTH(dateof) AS VARCHAR(2)) + '-' + CAST(YEAR(dateof) AS VARCHAR(4)) AS EffDate,
             rank() over (partition by manufacturer, CAST(MONTH(dateof) AS VARCHAR(2)) + '-' + CAST(YEAR(dateof) AS VARCHAR(4)) order by Prefer) as seqnum
      from Table1 t
     ),
     r1 as (
      select r.*
      from r
      where seqnum = 1
     )
select r.*
from r
where r.seqnum = 1 
or
(
  r.Status = 'ComputerUninstalled' and 
  exists ( Select 1 
           from  r1 
           where r1.Manufacturer = r.Manufacturer
           and   r1.EffDate = r.EffDate
           and   r1.Status = 'ComputerOld' )
  and   r.seqNum = ( Select Min(SeqNum) From r as r2
                      Where r2.Manufacturer = r.Manufacturer
                      And   r2.EffDate = r.EffDate
                      And   r2.SeqNum > 1 )          
)
or
(
  r.Status = 'ComputerInstalled' and 
  exists ( Select 1 
           from  r1 
           where r1.Manufacturer = r.Manufacturer
           and   r1.EffDate = r.EffDate
           and   r1.Status = 'ComputerNew' )
  and   r.seqNum = ( Select Min(SeqNum) From r as r2
                      Where r2.Manufacturer = r.Manufacturer
                      And   r2.EffDate = r.EffDate
                      And   r2.SeqNum > 1 )          
);

注意:我得到的记录多于预期结果集所示的2条记录。但是根据你的描述,我相信你在预期的结果中犯了一个错误。 2014年5月HP1910有6台“ComputerInstalled”,首选为30台。其中4台为5月1日,其中2台为5月2日。你遗漏了5月2日的记录。除此之外,这个结果集符合您的预期结果,并且应该适用于更大的数据集,我相信。

答案 2 :(得分:1)

我认为这应该给你你想要的东西:

WITH sq AS
( SELECT *, RANK() OVER (PARTITION BY Manufacturer,DateOF ORDER BY Prefer) AS RankPrefer
  FROM table1
)
SELECT *
FROM   sq
WHERE  RankPrefer <= (SELECT TOP 1 RankPrefer FROM sq WHERE Status != 'ComputerNew' ORDER BY RankPrefer)

Here is the SqlFiddle