Ars*_*nko 1 sql t-sql group-by
我有一个(似乎是)非常简单的问题,但在搜索了几个小时之后,我找不到任何有用的东西.
这是问题所在:
在Microsoft SQL中,我有一个表,其中列A存储一些数据.该数据可以包含重复项(即,两列或更多行对于列A具有相同的值).
我可以很容易地找到重复做:
select A, count(A) as CountDuplicates
from TableName
group by A having (count(A) > 1)
Run Code Online (Sandbox Code Playgroud)
现在,我想要检索其他列的值,假设乙和Ç.当然,即使对于共享相同A值的行,这些B和C值也可能不同,但对我来说无关紧要.我只想要任何B值和任何C值,第一个,最后一个或随机的一个.
如果我有一个小桌子和一两列要检索,我会做类似的事情:
select A, count(A) as CountDuplicates, (
select top 1 child.B from TableName as child where child.A = base.A) as B
)
from TableName as base group by A having (count(A) > 1)
Run Code Online (Sandbox Code Playgroud)
问题是我有更多的行可以获得,并且表格非常大,因此选择几个孩子会有很高的性能成本.
那么,是否有一个不那么难看的纯SQL解决方案呢?
不确定我的问题是否足够清楚,所以我举一个基于AdventureWorks数据库的例子.假设我想列出可用的州,并为每个州提供其代码,城市(任何城市)和地址(任何地址).最简单,最低效的方法是:
var q = from c in data.StateProvinces select new { c.StateProvinceCode, c.Addresses.First().City, c.Addresses.First().AddressLine1 };
Run Code Online (Sandbox Code Playgroud)
在LINQ-to-SQL中,将为181个状态中的每一个执行两次选择,因此363选择.我的情况是,我正在寻找一种方法,最多可以选择182个.
Chr*_*eld 10
ROW_NUMBER
CTE中的功能是实现此目的的方法.例如:
DECLARE @mytab TABLE (A INT, B INT, C INT)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 1, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 1, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 2, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (1, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (2, 2, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 3, 1)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 3, 2)
INSERT INTO @mytab ( A, B, C ) VALUES (3, 3, 3)
;WITH numbered AS
(
SELECT *, rn=ROW_NUMBER() OVER (PARTITION BY A ORDER BY B, C)
FROM @mytab AS m
)
SELECT *
FROM numbered
WHERE rn=1
Run Code Online (Sandbox Code Playgroud)
正如我在对HLGEM和Philip Kelley的评论中提到的,他们对聚合函数的简单使用并不一定会为每个A组返回一个"可靠"记录; 相反,它可以从许多单独的行返回列值,所有行都拼接在一起,好像它们是单个记录一样.例如,如果这是一个PERSON表,PersonID是"A"列,并且不同的联系人记录(例如,Home和Word),您最终可能会返回该人的本地城市,但他们的办公室邮政编码 - 以及这显然是在寻找麻烦.
在这里使用ROW_NUMBER与CTE一起使用起来有点困难,因为语法很笨拙.但它已经成为一种非常常见的模式,所以最好去了解它.
在我的样本中,我定义了一个CTE,它rn
在表格中添加了一个额外的列(代表"行号"),它本身按A列分组.甲SELECT
该结果,过滤,只有那些具有1(即,第一记录发现A的该值),返回每个A组"固体"的记录的行数-在我的上述例子中,你会肯定要获得工作或家庭地址,但不能将两者的元素混合在一起.
我担心您想要字段b和c的任何旧值。如果它们毫无意义,那么为什么要归还它们呢?
如果这真的没关系(老实说,我无法想象会出现这种情况,但这就是您所说的话),并且b和c的值甚至不必来自同一记录,请分组通过使用mon或max是必经之路。如果想要所有字段的特定记录的值,则更为复杂。
select A, count(A) as CountDuplicates, min(B) as B , min(C) as C
from TableName as base
group by A
having (count(A) > 1)
Run Code Online (Sandbox Code Playgroud)