2013-11-06 3 views
21

У меня есть запрос к большому количеству больших таблиц (строк и столбцов) с несколькими объединениями, однако в одной из таблиц есть несколько повторяющихся строк данных, вызывающих проблемы для моего запроса. Поскольку это только чтение в реальном времени из другого отдела, я не могу исправить эти данные, однако я пытаюсь предотвратить проблемы в моем запросе.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 десятков столбцов и 100K строк)

Мой первый инстинкт должен был выполнить отчетливый дал мне около 80K строк:

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: Просто хотел отметить: Эти записи являются дубликатами, основанные на неключевых/Неиндексированные поле ID, перечисленных выше. Идентификатор - это текстовое поле, которое хотя и имеет одно и то же значение, это другой случай, чем другие данные, вызывающие проблему.

+3

Похоже, строки не являются истинными дубликатами. Некоторые столбцы должны быть разными, иначе '' distinct * '' не будет возвращать все строки. Можете ли вы уточнить, что делает строку дубликат? – acfrancis

+0

Просьба представить желаемый результат для этой таблицы 'объявить @t таблицу (ID INT, имя символ (1)) вставка @t значения (1, 'а'), (1, 'б'), (1 , 'a'), (2, 'a'), (2, 'c') ' –

+1

Вы можете использовать CTE с ROW_NUMBER() OVER (PARTITION BY FirstName, LastName ORDER BY ID/DATE DESC) Как orderID', а затем выберите, где этот столбец равен одному из CTE. @acfrancis прав; вам нужно определить первичный ключ вашего вывода и использовать его для вашего раздела по столбцам. –

ответ

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') 
; 
+1

Если вы не контролируете окончательную базу данных, вы можете обнаружить, что она чувствительна к регистру (http://stackoverflow.com/questions/1411161/sql-server-check-case-sensitivity). Мое предложение состоит в том, чтобы поместить 'IDNo' в' UCASE() 'просто для того, чтобы оставаться на безопасной стороне. – mucio

+0

После выполнения полного теста выглядит, что POC в скрипке не получается так, как ожидалось. Это потому, что любой столбец с другим значением сделает строку отличной. – Dave

+0

@mucio хорошая точка, когда я получу это решение, я обязательно буду использовать верхний регистр ключей. – Dave

0

Попробуйте

SELECT * 
FROM people P 
where P.IDNo in (SELECT DISTINCT IDNo 
       FROM people) 
+1

Хорошая идея. Пробовал это, и он все еще показывает дубликаты. Похоже, что IN сравнивается неслучайно. Я попытался обмануть, обернув P.IDNo в Upper() и тот же для отдельного IDNo, но он все еще показал обманы. Doh. – Dave

1

После тщательного рассмотрения этого dillema имеет несколько различных решений:

Совокупные Everything Используйте агрегат на каждой колонке получить самую большую или наименьшую стоимость поля. Это то, что я делаю, так как он принимает 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 
2

Добавить столбец идентификаторов (PeopleID), а затем использовать коррелированный подзапрос, чтобы вернуть первый значение для каждого значения.

SELECT * 
FROM People p 
WHERE PeopleID = (
    SELECT MIN(PeopleID) 
    FROM People 
    WHERE IDNo = p.IDNo 
) 
2

В зависимости от характера повторяющихся строк, похоже, что все, что вы хотите, это чувствительность к регистру на этих столбцах. Настройка параметров сортировки на этих столбцов должно быть то, что вы после:

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

26

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 ... 
+0

Как это выполнить, если, например, таблица людей намного больше, чем таблица x? – HansHarhoff

+0

@HansHarhoff: проверьте план выполнения. Но неважно, если одна таблица больше, чем другая, - если требование состоит в том, чтобы вернуть все строки из 'x' и только« последние »из« людей », нет другого способа сделать это. –

Смежные вопросы