如何只为列的每个唯一值选择第一行


96

假设我有一张客户地址表:

CName           |   AddressLine
-------------------------------
John Smith      | 123 Nowheresville
Jane Doe        | 456 Evergreen Terrace
John Smith      | 999 Somewhereelse
Joe Bloggs      | 1 Second Ave

在表中,一个客户(例如John Smith)可以有多个地址。我需要此表的选择查询,以仅返回在“ CName”中存在重复项的情况下找到的第一行。对于此表,它应返回除第3个(或第1个-这两个地址中的任何一个都可以,但只能返回一个)之外的所有行。是否可以根据服务器是否之前已经查看过列值将关键字添加到SELECT查询中进行过滤?

Answers:


125

如果您说自己不在乎使用哪个地址,那么这是一个非常简单的答案。

SELECT
    CName, MIN(AddressLine)
FROM
    MyTable
GROUP BY
    CName

如果您想根据“插入的”列作为第一个,则使用不同的查询

SELECT
    M.CName, M.AddressLine,
FROM
    (
    SELECT
        CName, MIN(Inserted) AS First
    FROM
        MyTable
    GROUP BY
        CName
    ) foo
    JOIN
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted

尽管在选择10列时可能不打算以此方式使用它。似乎它也不能接受位类型的列。
nuit9 2011年

1
@ nuit9:当然,它不适用于bit和10列。这些事实都与您无关。您将使用第二种技术或Ben Thul的技术。我回答了您的具体要求,并提供了有关如何更一般地解决问题的指导。
gbn

第一部分确实适用于多列,尽管不适用于位型列。我在MS SQL Server 2016中对此进行了测试。
netfed

24

在SQL 2k5 +中,您可以执行以下操作:

;with cte as (
  select CName, AddressLine,
  rank() over (partition by CName order by AddressLine) as [r]
  from MyTable
)
select CName, AddressLine
from cte
where [r] = 1

5
请解释排名,划分和[r]的作用
罗伯托

10

您可以使用row_number()获取行的行号。它使用over命令-该partition by子句指定何时重新开始编号并order by选择要对行号进行排序的顺序。即使在order by查询末尾添加了,它也会over在编号时保留命令中的顺序。

select *
from mytable
where row_number() over(partition by Name order by AddressLine) = 1

6
在postgresql中,WHERE子句中不允许使用窗口函数
ekanna 2015年

3
MS-SQL均不允许这样做。
Mixxiphoid

1
ROW_NUMBER()Where在Teradata 中的子句中也不起作用
Pirate X

6

您可以使用如下row_numer() over(partition by ...)语法:

select * from
(
select *
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row
from myTable
) as a
where row = 1

它的作用是创建一个名为的列row,该列是一个计数器,每次看到该列时都会递增CName,并用索引这些出现AddressLine。通过征收where row = 1,可以选择CNameAddressLine来首字母顺序排列。如果order bydesc的话,那就挑CNameAddressLine是最后的字母顺序。


1

这将为您每个重复行提供一行。它还将为您提供位类型列,并且至少在MS Sql Server中有效。

(select cname, address 
from (
  select cname,address, rn=row_number() over (partition by cname order by cname) 
  from customeraddresses  
) x 
where rn = 1) order by cname

如果要查找所有重复项,只需将rn = 1更改为rn>1。希望这会有所帮助

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.