我有一个查询,其中我根据3列对行进行排名。 我成功地这样做了,除了如果任何行在这3列中包含相同的数据,即使它在输出中不连续,它也会给它下一个等级。我希望如果任何行匹配这些列中的数据,只有当它在连续的行中时才应该给出下一个等级,如果没有那么它应该再次给它作为1的等级。 我尝试了以下代码:
SELECT DISTINCT DENSE_RANK () OVER (PARTITION BY Patient_ID,
Opnametype,
afdelingscode ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd) AS rnk,
*
FROM t_opnames
ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd
输出为:
rnk Opnamenummer Patient_ID afdelingscode Opnametype Specialismen OntslagDatumTijd ...
1 2983800 100006 RD8-GH MAU Inpatient-E GM 2014-09-01 14:50:00.000
2 2983800 100006 RD8-GH MAU Inpatient-E GM 2014-09-02 19:32:00.000
1 2983800 100006 RD8-GH Ward 08 Inpatient-E GM 2014-09-03 17:12:00.000
1 2983800 100006 RD8-GH Endo Inpatient-E GM 2014-09-09 09:06:00.000
2 2983800 100006 RD8-GH Ward 08 Inpatient-E GM 2014-09-17 17:00:00.000
3 2983800 100006 RD8-GH Ward 08 Inpatient-E GM 2014-10-01 17:15:00.000
因此,除了最后两行之外,所有行都是正确的。我希望它们的等级为1和2而不是2和3,因为行有" RD8-GH Endo"在他们之间。 那我怎么能这样做呢?
答案 0 :(得分:1)
您可以使用相关子查询来实现此目的。使用类似这样的东西
DECLARE @t_opnames TABLE
(
Opnamenummer INT,
Patient_ID INT,
afdelingscode VARCHAR(100),
Opnametype VARCHAR(100),
Specialismen CHAR(2),
OntslagDatumTijd DATETIME
)
Insert into @t_opnames
SELECT 2983800 ,100006, 'RD8-GH MAU', 'Inpatient-E', 'GM', '2014-09-01 14:50:00.000'
UNION ALL SELECT 2983800 ,100006, 'RD8-GH MAU', 'Inpatient-E', 'GM', '2014-09-02 19:32:00.000'
UNION ALL SELECT 2983800 ,100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM', '2014-09-03 17:12:00.000'
UNION ALL SELECT 2983800 ,100006, 'RD8-GH Endo', 'Inpatient-E', 'GM', '2014-09-09 09:06:00.000'
UNION ALL SELECT 2983800 ,100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM', '2014-09-17 17:00:00.000'
UNION ALL SELECT 2983800 ,100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM', '2014-10-01 17:15:00.000'
;WITH CTE as
(
SELECT DENSE_RANK() OVER(ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd) rnk,*
FROM @t_opnames
)
SELECT rnk-ISNULL((
SELECT MAX(rnk)
FROM CTE c2
WHERE c2.Opnamenummer <= c1.Opnamenummer
AND c2.SPECIALISMEN <= c1.SPECIALISMEN
AND c2.OntslagDatumTijd <= c1.OntslagDatumTijd
AND c2.rnk < c1.rnk
AND (c2.Patient_ID <> c1.Patient_ID
OR c2.Opnametype <> c1.Opnametype
OR c2.afdelingscode <> c1.afdelingscode)),0) rnk,Patient_ID, Opnametype,afdelingscode,Opnamenummer, SPECIALISMEN, OntslagDatumTijd
FROM CTE c1
ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd
答案 1 :(得分:1)
最后我得到了我的查询解决方案,现在我得到了我想要的输出,并且在3秒内运行超过75k +行。我使用的代码是:
SELECT DISTINCT ROW_NUMBER () OVER (ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd) AS rownum,
* INTO #temp
FROM t_opnames
ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd;
WITH CTE
AS (SELECT *,
ROW_NUMBER () OVER (ORDER BY rownum) - ROW_NUMBER () OVER (PARTITION BY Patient_ID,
Opnametype,
afdelingscode ORDER BY rownum) AS RowGroup
FROM #temp)
SELECT ROW_NUMBER () OVER (PARTITION BY RowGroup,
Patient_ID,
Opnametype,
afdelingscode ORDER BY rownum) AS GroupSequence,
*
FROM CTE
ORDER BY rownum;
DROP TABLE #temp;
我提到了在此page
发布的示例答案 2 :(得分:0)
这并没有直接回答这个问题,但我的目的是解释为什么你所尝试的并不像你期望的那样工作。
您的问题是由PARTITION
引起的。如果您从PARTITION
子句中删除非唯一列,则会留下afdelingscode
。因此,简单来说,您的PARTITION
正在对数据进行分组,如下所示:
RD8-GH Endo
RD8-GH MAU
RD8-GH MAU
RD8-GH Ward 08
RD8-GH Ward 08
RD8-GH Ward 08
ORDER BY
子句确定了PARTITION
中的顺序,因此再次移除非唯一列会为您生成ORDER BY OntslagDatumTijd
,生成此内容,按日期列排序,注意分区仍由afdelingscode
分隔:
afdelingscode OntslagDatumTijd
RD8-GH Endo 2014-09-09 09:06:00.000
RD8-GH MAU 2014-09-01 14:50:00.000
RD8-GH MAU 2014-09-02 19:32:00.000
RD8-GH Ward 08 2014-09-03 17:12:00.000
RD8-GH Ward 08 2014-09-17 17:00:00.000
RD8-GH Ward 08 2014-10-01 17:15:00.000
然后将排名应用于这些分区。输出结果为:
rnk afdelingscode OntslagDatumTijd
1 RD8-GH Endo 2014-09-09 09:06:00.000
1 RD8-GH MAU 2014-09-01 14:50:00.000
2 RD8-GH MAU 2014-09-02 19:32:00.000
1 RD8-GH Ward 08 2014-09-03 17:12:00.000
2 RD8-GH Ward 08 2014-09-17 17:00:00.000
3 RD8-GH Ward 08 2014-10-01 17:15:00.000
因此根据您指定的方式对其进行排名,输出中的问题是因为在您选择的最后(取出非唯一列)是按日期列OntslagDatumTijd
排序,这给出了你:
rnk afdelingscode OntslagDatumTijd
1 RD8-GH MAU 2014-09-01 14:50:00.000
2 RD8-GH MAU 2014-09-02 19:32:00.000
1 RD8-GH Ward 08 2014-09-03 17:12:00.000
1 RD8-GH Endo 2014-09-09 09:06:00.000
2 RD8-GH Ward 08 2014-09-17 17:00:00.000
3 RD8-GH Ward 08 2014-10-01 17:15:00.000
如果发布的其他答案不符合您的要求,我会继续查看。
<强>参考:强>
PARTITION BY 将查询结果集划分为多个分区。窗户 函数分别应用于每个分区并进行计算 重启每个分区。
ORDER BY子句定义每个子行中的行的逻辑顺序 结果集的分区。也就是说,它指定逻辑顺序 其中执行窗口函数计算。
这是一个潜在的解决方案,可能会对您使用的数据大小产生性能问题,但您可以对其进行测试:
-- sets up your dummy data
CREATE TABLE #t_opnames
(
Opnamenummer INT ,
Patient_ID INT ,
afdelingscode NVARCHAR(20) ,
Opnametype NVARCHAR(20) ,
Specialismen NVARCHAR(20) ,
OntslagDatumTijd DATETIME
);
INSERT INTO #t_opnames
( Opnamenummer, Patient_ID, afdelingscode, Opnametype, Specialismen,
OntslagDatumTijd )
VALUES ( 2983800, 100006, 'RD8-GH MAU', 'Inpatient-E', 'GM',
'2014-09-01 14:50:00.000' ),
( 2983800, 100006, 'RD8-GH MAU', 'Inpatient-E', 'GM',
'2014-09-02 19:32:00.000' ),
( 2983800, 100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM',
'2014-09-03 17:12:00.000' ),
( 2983800, 100006, 'RD8-GH Endo', 'Inpatient-E', 'GM',
'2014-09-09 09:06:00.000' ),
( 2983800, 100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM',
'2014-09-17 17:00:00.000' ),
( 2983800, 100006, 'RD8-GH Ward 08', 'Inpatient-E', 'GM',
'2014-10-01 17:15:00.000' )
-- I've added a row number to your data to enable iteration over the data
SELECT ROW_NUMBER() OVER ( ORDER BY OntslagDatumTijd ) AS rn ,
*
INTO #temp
FROM #t_opnames
ORDER BY OntslagDatumTijd
-- this will iterate over the rows and apply the rankings
;WITH cte AS (
SELECT *, 1 AS rnk
FROM #temp
WHERE rn = 1
UNION ALL
SELECT t.*, CASE WHEN cte.afdelingscode = t.afdelingscode
THEN cte.rnk + 1
ELSE 1
END AS rnk
FROM #temp t
INNER JOIN cte ON cte.rn +1 = t.rn
)
SELECT * FROM cte
DROP TABLE #t_opnames
DROP TABLE #temp
对于较大的数据集,您将达到MAXRECURSION
限制,您需要在最终SELECT
之后使用以下内容修改限制:
SELECT * FROM cte
OPTION (MAXRECURSION 0)
将此值设置为0
不会产生任何限制,如果您事先知道,可以将此数字设置为数据集的大小。