Как выбрать только первые строки для каждого уникального значения столбца - PullRequest
76 голосов
/ 11 января 2011

Допустим, у меня есть таблица адресов клиентов:

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

В таблице один клиент, такой как Джон Смит, может иметь несколько адресов. Мне нужен запрос на выборку для этой таблицы, чтобы он возвращал только первую найденную строку, где есть дубликаты в 'CName'. Для этой таблицы она должна вернуть все строки, кроме 3-й (или 1-й - любой из этих двух адресов в порядке, но может быть возвращен только один). Есть ли ключевое слово, которое я могу добавить к запросу SELECT для фильтрации на основе того, видел ли сервер значение столбца ранее?

Ответы [ 5 ]

111 голосов
/ 11 января 2011

Очень простой ответ, если вы говорите, что вам все равно, какой адрес используется.

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
20 голосов
/ 12 января 2011

В 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
10 голосов
/ 18 апреля 2013

Вы можете использовать row_number(), чтобы получить номер строки в строке. Он использует команду over - в предложении partition by указывается, когда нужно перезапускать нумерацию, а order by выбирает, на что упорядочить номер строки. Даже если вы добавите order by в конец вашего запроса, при нумерации он сохранит порядок в команде over.

select *
from mytable
where row_number() over(partition by Name order by AddressLine) = 1
4 голосов
/ 01 марта 2018

Вы можете использовать синтаксис 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 можно выбрать CName, чей AddressLine стоит в алфавитном порядке. Если бы order by было desc, тогда он выбрал бы CName, чей AddressLine был последним в алфавитном порядке.

1 голос
/ 09 сентября 2018

Это даст вам один ряд каждого дублированного ряда. Это также даст вам столбцы битового типа, и это работает, по крайней мере, в 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. Надеюсь, это поможет

...