Sql server 如何使用t-sql选择表中一列和一个重复的最高值
我有一个表格,其中包含了测试在不同样本上执行的一些数据,这些样本具有不同的期望值(P1比S1好,S1比S3好,S3比S2好),有时这些测试中的任何一个都可以重复。如果测试失败,必须有人重新进行 我希望我的查询只显示最佳样本(P1>S1>S3>S2)和重复数据(而不是原始数据) 下面的查询可以工作,但正如您所看到的,它相当长且复杂。我还是一个初级SQL人员,那么如何用更短/更好的查询完成同样的事情呢 我正在努力学习更好的SQL,所以我不必总是问这些类型的问题,所以解释一下为什么您的查询工作得更好会非常有帮助Sql server 如何使用t-sql选择表中一列和一个重复的最高值,sql-server,tsql,select,subquery,repeat,Sql Server,Tsql,Select,Subquery,Repeat,我有一个表格,其中包含了测试在不同样本上执行的一些数据,这些样本具有不同的期望值(P1比S1好,S1比S3好,S3比S2好),有时这些测试中的任何一个都可以重复。如果测试失败,必须有人重新进行 我希望我的查询只显示最佳样本(P1>S1>S3>S2)和重复数据(而不是原始数据) 下面的查询可以工作,但正如您所看到的,它相当长且复杂。我还是一个初级SQL人员,那么如何用更短/更好的查询完成同样的事情呢 我正在努力学习更好的SQL,所以我不必总是问这些类型的问题,所以解释一下为什么您的查询工作得更好会
DECLARE @TempTable TABLE (Sample_ID varchar(10), TestRepeat int, TestResult varchar(1))
-- In the end, ONLY the samples with Y should be displayed
INSERT INTO @TempTable VALUES('61-0001-P1', 0, 'R') -- 1 Y
INSERT INTO @TempTable VALUES('61-0002-P1', 0, 'R') -- 2 Y
INSERT INTO @TempTable VALUES('61-0003-S1', 0, 'S') -- 3 Y
INSERT INTO @TempTable VALUES('61-0004-S1', 0, 'R') -- 4 Y
INSERT INTO @TempTable VALUES('61-0005-P1', 0, 'I') -- 5
INSERT INTO @TempTable VALUES('61-0005-P1', 1, 'S') -- 6 Y
INSERT INTO @TempTable VALUES('61-0006-P1', 0, 'S') -- 7 Y
INSERT INTO @TempTable VALUES('61-0006-S3', 0, 'R') -- 8
INSERT INTO @TempTable VALUES('61-0007-P1', 0, 'S') -- 9 Y
INSERT INTO @TempTable VALUES('61-0008-S3', 0, 'I') -- 10
INSERT INTO @TempTable VALUES('61-0008-S3', 1, 'R') -- 11 Y
INSERT INTO @TempTable VALUES('61-0009-P1', 0, 'R') -- 12 Y
INSERT INTO @TempTable VALUES('61-0009-S1', 0, 'S') -- 13
INSERT INTO @TempTable VALUES('61-0010-P1', 0, 'S') -- 14 Y
INSERT INTO @TempTable VALUES('61-0011-S3', 0, 'S') -- 15 Y
DECLARE @TempTable1 TABLE (Subject_ID varchar(7), Sample_ID varchar(10), SampleOrder int, TestRepeat int, TestResult varchar(1))
INSERT @TempTable1
SELECT LEFT(Sample_ID,7) AS Subject_ID,
Sample_ID,
SampleOrder =
CASE
WHEN RIGHT(Sample_ID,2) = 'P1' THEN 4
WHEN RIGHT(Sample_ID,2) = 'S1' THEN 3
WHEN RIGHT(Sample_ID,2) = 'S3' THEN 2
WHEN RIGHT(Sample_ID,2) = 'S2' THEN 1
END,
TestRepeat,
TestResult
FROM @TempTable
ORDER BY Subject_ID, SampleOrder;
--SELECT * FROM @TempTable1;
DECLARE @TempTable2 TABLE (Sample_ID varchar(10), TestRepeat int, TestResult varchar(1))
INSERT @TempTable2 SELECT
tt1.Sample_ID,
tt1.TestRepeat,
tt1.TestResult
FROM @TempTable1 tt1
INNER JOIN (
SELECT Subject_ID, MAX(SampleOrder) AS Max_SampleOrder
FROM @TempTable1
GROUP BY Subject_ID) subQ1
ON (tt1.Subject_ID=subQ1.Subject_ID AND tt1.SampleOrder=subQ1.Max_SampleOrder)
ORDER BY tt1.Sample_ID;
SELECT tt2.Sample_ID,
tt2.TestRepeat,
tt2.TestResult
FROM @TempTable2 tt2
INNER JOIN (
SELECT Sample_ID, MAX(TestRepeat) AS Max_TestRepeat
FROM @TempTable2
GROUP BY Sample_ID) subQ
ON (tt2.Sample_ID = subQ.Sample_ID AND tt2.TestRepeat=subq.Max_TestRepeat)
ORDER BY tt2.Sample_ID, tt2.TestResult;
尝试使用公共表表达式。您不必创建所有的表变量,它可能会更干净一些。下面是一个示例,我保留了源数据示例中的原始表变量
DECLARE @TempTable TABLE (Sample_ID varchar(10), TestRepeat int, TestResult varchar(1))
-- In the end, ONLY the samples with Y should be displayed
INSERT INTO @TempTable VALUES('61-0001-P1', 0, 'R') -- 1 Y
INSERT INTO @TempTable VALUES('61-0002-P1', 0, 'R') -- 2 Y
INSERT INTO @TempTable VALUES('61-0003-S1', 0, 'S') -- 3 Y
INSERT INTO @TempTable VALUES('61-0004-S1', 0, 'R') -- 4 Y
INSERT INTO @TempTable VALUES('61-0005-P1', 0, 'I') -- 5
INSERT INTO @TempTable VALUES('61-0005-P1', 1, 'S') -- 6 Y
INSERT INTO @TempTable VALUES('61-0006-P1', 0, 'S') -- 7 Y
INSERT INTO @TempTable VALUES('61-0006-S3', 0, 'R') -- 8
INSERT INTO @TempTable VALUES('61-0007-P1', 0, 'S') -- 9 Y
INSERT INTO @TempTable VALUES('61-0008-S3', 0, 'I') -- 10
INSERT INTO @TempTable VALUES('61-0008-S3', 1, 'R') -- 11 Y
INSERT INTO @TempTable VALUES('61-0009-P1', 0, 'R') -- 12 Y
INSERT INTO @TempTable VALUES('61-0009-S1', 0, 'S') -- 13
INSERT INTO @TempTable VALUES('61-0010-P1', 0, 'S') -- 14 Y
INSERT INTO @TempTable VALUES('61-0011-S3', 0, 'S') -- 15 Y
;with CTE1 as
(
SELECT LEFT(Sample_ID,7) AS Subject_ID,
Sample_ID,
SampleOrder =
CASE
WHEN RIGHT(Sample_ID,2) = 'P1' THEN 4
WHEN RIGHT(Sample_ID,2) = 'S1' THEN 3
WHEN RIGHT(Sample_ID,2) = 'S3' THEN 2
WHEN RIGHT(Sample_ID,2) = 'S2' THEN 1
END,
TestRepeat,
TestResult
FROM @TempTable
),
CTE2 as
(
SELECT
tt1.Sample_ID,
tt1.TestRepeat,
tt1.TestResult
FROM CTE1 tt1
INNER JOIN (
SELECT Subject_ID, MAX(SampleOrder) AS Max_SampleOrder
FROM CTE1
GROUP BY Subject_ID) subQ1
ON (tt1.Subject_ID=subQ1.Subject_ID AND tt1.SampleOrder=subQ1.Max_SampleOrder)
),
CTE3 as
(
SELECT tt2.Sample_ID,
tt2.TestRepeat,
tt2.TestResult
FROM CTE2 tt2
INNER JOIN (
SELECT Sample_ID, MAX(TestRepeat) AS Max_TestRepeat
FROM CTE2
GROUP BY Sample_ID) subQ
ON (tt2.Sample_ID = subQ.Sample_ID AND tt2.TestRepeat=subq.Max_TestRepeat)
)
select *
from CTE3;
它生成的结果与示例相同,没有那么多表变量。它也应该比表变量更有效
下面是我的博客的链接,其中有几个常用表表达式的示例。
希望这有帮助。如果您有任何问题,请告诉我。您可以在此子查询中使用
select Sample_ID, TestRepeat, TestResult
from
(
select Sample_ID, TestRepeat, TestResult,
row_number() over(partition by left(Sample_ID, 7)
order by case right(Sample_ID,2)
when 'P1' then 1
when 'S1' then 2
when 'S3' then 3
when 'S2' then 4
end, TestRepeat desc) as rn
from @TempTable
) as T
where rn = 1
order by Sample_ID
您可以在上测试查询
说明:row\u number
将枚举1
中的行。partition by
子句控制何时再次从1
开始编号,而order by
子句指定编号顺序。上面使用的over()
子句将为您感兴趣的行提供row\u number()
的1
。在查询的where子句中不可能使用row\u number()
,因此您必须使用派生表才能根据row\u number()的结果筛选行您可能也可以对子查询执行相同的操作,但这将更加混乱。您可以在此处找到对排序函数的良好理解: