SQL Left Только первое совпадение
У меня есть запрос против большого числа больших таблиц (строк и столбцов) с несколькими объединениями, однако в одной из таблиц есть несколько повторяющихся строк данных, вызывающих проблемы для моего запроса. Поскольку это только чтение в реальном времени из другого отдела, я не могу исправить эти данные, однако я пытаюсь предотвратить проблемы в моем запросе.
Учитывая, что мне нужно добавить эти данные дерьма в качестве левого соединения к моему хорошему запросу. Набор данных выглядит так:
IDNo FirstName LastName ...
-------------------------------------------
uqx bob smith
abc john willis
ABC john willis
aBc john willis
WTF jeff bridges
sss bill doe
ere sally abby
wtf jeff bridges
...
(около 2 десятков столбцов и 100 тыс. строк)
Мой первый инстинкт состоял в том, чтобы выполнить отчет, который дал мне около 80 тыс. строк:
SELECT DISTINCT P.IDNo
FROM people P
Но когда я пытаюсь сделать следующее, я возвращаю все строки:
SELECT DISTINCT P.*
FROM people P
ИЛИ
SELECT
DISTINCT(P.IDNo) AS IDNoUnq
,P.FirstName
,P.LastName
...etc.
FROM people P
Тогда я подумал, что я буду выполнять агрегатную функцию FIRST() во всех столбцах, однако это тоже не так. Синтаксически я делаю что-то неправильно здесь?
Update:
Просто хотелось бы отметить: эти записи являются дубликатами на основе неиндексного/неиндексированного поля идентификатора, указанного выше. Идентификатор - это текстовое поле, которое хотя и имеет одно и то же значение, это другой случай, чем другие данные, вызывающие проблему.
Ответы
Ответ 1
Оказывается, я делал это неправильно, мне нужно было выполнить вложенный выбор сначала только из важных столбцов и сделать отдельный выбор, чтобы предотвратить столбцы корзины "уникальных" данных от развращения моих хороших данных. Следующее, похоже, решило проблему... но позже я попробую полный набор данных.
SELECT DISTINCT P2.*
FROM (
SELECT
IDNo
, FirstName
, LastName
FROM people P
) P2
Ниже приведены некоторые данные воспроизведения: http://sqlfiddle.com/#!3/050e0d/3
CREATE TABLE people
(
[entry] int
, [IDNo] varchar(3)
, [FirstName] varchar(5)
, [LastName] varchar(7)
);
INSERT INTO people
(entry,[IDNo], [FirstName], [LastName])
VALUES
(1,'uqx', 'bob', 'smith'),
(2,'abc', 'john', 'willis'),
(3,'ABC', 'john', 'willis'),
(4,'aBc', 'john', 'willis'),
(5,'WTF', 'jeff', 'bridges'),
(6,'Sss', 'bill', 'doe'),
(7,'sSs', 'bill', 'doe'),
(8,'ssS', 'bill', 'doe'),
(9,'ere', 'sally', 'abby'),
(10,'wtf', 'jeff', 'bridges')
;
Ответ 2
distinct
не функция. Он всегда работает со всеми столбцами списка выбора.
Ваша проблема - типичная проблема "наибольшего N на группу", которая может быть легко решена с помощью оконной функции:
select ...
from (
select IDNo,
FirstName,
LastName,
....,
row_number() over (partition by lower(idno) order by firstname) as rn
from people
) t
where rn = 1;
Используя предложение order by
, вы можете выбрать, какой из дубликатов вы хотите выбрать.
Вышеприведенное может быть использовано в левом соединении:
select ...
from x
left join (
select IDNo,
FirstName,
LastName,
....,
row_number() over (partition by lower(idno) order by firstname) as rn
from people
) p on p.idno = x=idno and p.rn = 1
where ...
Ответ 3
Добавьте столбец идентификатора (PeopleID), а затем используйте коррелированный подзапрос, чтобы вернуть первое значение для каждого значения.
SELECT *
FROM People p
WHERE PeopleID = (
SELECT MIN(PeopleID)
FROM People
WHERE IDNo = p.IDNo
)
Ответ 4
В зависимости от характера повторяющихся строк, похоже, что все, что вам нужно, - это чувствительность к регистру для этих столбцов. Настройка сортировки по этим столбцам должна быть следующей:
SELECT DISTINCT p.IDNO COLLATE SQL_Latin1_General_CP1_CI_AS, p.FirstName COLLATE SQL_Latin1_General_CP1_CI_AS, p.LastName COLLATE SQL_Latin1_General_CP1_CI_AS
FROM people P
http://msdn.microsoft.com/en-us/library/ms184391.aspx
Ответ 5
После тщательного рассмотрения эта диллема имеет несколько разных решений:
Совокупное все
Используйте агрегат для каждого столбца, чтобы получить наибольшее или минимальное значение поля. Это то, что я делаю, так как он принимает 2 частично заполненных записи и "объединяет" данные.
http://sqlfiddle.com/#!3/59cde/1
SELECT
UPPER(IDNo) AS user_id
, MAX(FirstName) AS name_first
, MAX(LastName) AS name_last
, MAX(entry) AS row_num
FROM people P
GROUP BY
IDNo
Получить первую (или последнюю запись)
http://sqlfiddle.com/#!3/59cde/23
-- ------------------------------------------------------
-- Notes
-- entry: Auto-Number primary key some sort of unique PK is required for this method
-- IDNo: Should be primary key in feed, but is not, we are making an upper case version
-- This gets the first entry to get last entry, change MIN() to MAX()
-- ------------------------------------------------------
SELECT
PC.user_id
,PData.FirstName
,PData.LastName
,PData.entry
FROM (
SELECT
P2.user_id
,MIN(P2.entry) AS rownum
FROM (
SELECT
UPPER(P.IDNo) AS user_id
, P.entry
FROM people P
) AS P2
GROUP BY
P2.user_id
) AS PC
LEFT JOIN people PData
ON PData.entry = PC.rownum
ORDER BY
PData.entry
Ответ 6
Попробуйте это
SELECT *
FROM people P
where P.IDNo in (SELECT DISTINCT IDNo
FROM people)