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


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

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

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

5 63

5 ответов:

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

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

в 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

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

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

можно использовать 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 идет последним в алфавитном порядке.

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