这是一个小小的破坏者:
平台是MS SQL 2008,但问题很普遍。
我有一个包含3列的表格表: CLIENT,DATE,DESTINATION_PREFERENCE
TABLE1
-------------------------------------------------------
CLIENT |DATE |DESTINATION_PREFERENCE
-------------------------------------------------------
Akme |2014-01 |1
Akme |2014-02 |6
Akme |2014-02 |3
Akme |2014-03 |5
Yutani |2014-01 |5
Yutani |2014-02 |8
Yutani |2014-03 |3
Yutani |2014-03 |5
我要做的事实上是两件事:
第一是非常简单,也是一个经典问题:
从每组CLIENT和DATE中选择一个最小DESTINATION_PREFERENCE的行。
换句话说,我们在CLIENT,DATE上进行GROUP BY,然后选择DESTINATION_PREFERENCE最低的行。
注意:我在DATE只使用YEAR和MONTH。
这可以通过RANK轻松解决:
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE
FROM
(
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE,
RANK() OVER (PARTITION BY CLIENT, DATE ORDER BY DESTINATION_PREFERENCE ASC) AS RANKING
FROM
#table1
) sq
WHERE
RANKING = 1
结果很好,我们选择每行CLIENT和DATE(YEAR,MONTH)中DESTINATION_PREFERENCE最低的行:
CLIENT DATE DESTINATION_PREFERENCE
Akma 2014-01 1
Akma 2014-02 3
Akma 2014-03 5
Yutani 2014-01 5
Yutani 2014-02 8
Yutani 2014-03 3
第二 - 现在来了困难的部分。我无法解决,需要一些建议:
如果DESTINATION_PREFERENCE为3,我仍然应该在其中包含行 DESTINATION_PREFERENCE等于6。
因此结果表值将有一个额外的行(第2行):
CLIENT DATE DESTINATION_PREFERENCE
Akma 2014-01 1
Akme 2014-02 6
Akma 2014-02 3
Akma 2014-03 5
Yutani 2014-01 5
Yutani 2014-02 8
Yutani 2014-03 3
我怎样才能将RANK()扩展到包含这样的任意规则? 要实施的示例规则:
如果组中DESTINATION_PREFERENCE的最高值为3,则包含来自同一组的值为6的行。
如果组中DESTINATION_PREFERENCE的最高值为9,则包含来自同一组的值为2的行。
如果组中DESTINATION_PREFERENCE的最高值为128,则包含来自同一组的值为312的行。
等等......有很多规则。
提前感谢您提示!
答案 0 :(得分:1)
我认为你的意思是如果最小目的地偏好是3,那么包括6.这意味着将“6”视为“3”,但仅限于“3”。
您可以使用窗口函数执行此操作,方法是输入“6-flag”:
SELECT CLIENT, DATE, DESTINATION_PREFERENCE
FROM (SELECT t1.*
RANK() OVER (PARTITION BY CLIENT, DATE
ORDER BY (CASE WHEN NumThrees > 0 AND DESTINATION_PREFERENCE = 6 THEN 3
ELSE DESTINATION_PREFERENCE END) ASC
) AS RANKING
FROM (SELECT t1.*,
SUM(CASE WHEN DESTINATION_PREFERENCE = 3 THEN 1 ELSE 0 END) as NumThrees
FROM #table1 t1
) t1
) sq
WHERE RANKING = 1 ;
如果你想在所有情况下将“6”视为“3”,那么你不需要子查询:
SELECT CLIENT, DATE, DESTINATION_PREFERENCE
FROM (SELECT t1.*
RANK() OVER (PARTITION BY CLIENT, DATE
ORDER BY (CASE WHEN DESTINATION_PREFERENCE = 6 THEN 3
ELSE DESTINATION_PREFERENCE END) ASC
) AS RANKING
FROM #table1 t1
) sq
WHERE RANKING = 1 ;
答案 1 :(得分:1)
您可以使用CTE添加额外的列,只需将3替换为6,9替换为2等。
DECLARE @t TABLE
(
client NVARCHAR(MAX) ,
date DATETIME ,
dest INT
)
INSERT INTO @t
VALUES ( 'Akme', '20140101', 1 ),
( 'Akme', '20140102', 3 ),
( 'Akme', '20140102', 6 ),
( 'Akme', '20140103', 5 ),
( 'Yutani', '20140104', 2 ),
( 'Yutani', '20140104', 7 ),
( 'Yutani', '20140104', 9 ),
( 'Yutani', '20140105', 7 );
WITH cte
AS ( SELECT client ,
date ,
dest ,
CASE dest
WHEN 6 THEN 3
WHEN 9 THEN 2
ELSE dest
END AS rndest
FROM @t
)
SELECT CLIENT ,
DATE ,
dest
FROM ( SELECT CLIENT ,
DATE ,
dest ,
RANK() OVER ( PARTITION BY CLIENT, DATE ORDER BY rndest ASC ) AS RANKING
FROM cte
) sq
WHERE RANKING = 1
输出:
CLIENT DATE dest
Akme 2014-01-01 00:00:00.000 1
Akme 2014-01-02 00:00:00.000 3
Akme 2014-01-02 00:00:00.000 6
Akme 2014-01-03 00:00:00.000 5
Yutani 2014-01-04 00:00:00.000 2
Yutani 2014-01-04 00:00:00.000 9
Yutani 2014-01-05 00:00:00.000 7
答案 2 :(得分:1)
您可以在等级中按顺序放置一个案例陈述:
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE
FROM
(
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE,
RANK() OVER (PARTITION BY CLIENT, DATE ORDER BY Case DESTINATION_PREFERENCE when 3 then 6 when 9 then 2 when 128 then 312 else DESTINATION_PREFERENCE END ASC)
AS RANKING
FROM
#table1
) sq
WHERE
RANKING = 1
答案 3 :(得分:1)
由于缺乏评级,不能对Gordon Linoff的帖子发表评论。但是,如果只有3是最小目的地,他的解决方案将起作用。如果最小值= 1且它将同时具有3和6,则它也将显示为6。
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE
FROM
(
SELECT
CLIENT,DATE,DESTINATION_PREFERENCE ,
RANK() OVER (PARTITION BY CLIENT, DATE ORDER BY DESTINATION_PREFERENCE ASC) AS RANKING,
MIN(DESTINATION_PREFERENCE ) OVER (PARTITION BY CLIENT, DATE) AS min_3
FROM
#table1
) sq
WHERE
RANKING = 1
OR (min_3 = 3 AND DESTINATION_PREFERENCE =6)