Только первое совпадение SQL Left Join

у меня есть запрос против большого количества больших таблиц (строк и столбцов) с несколькими соединениями, однако одна из таблиц имеет несколько повторяющихся строк данных, вызывающих проблемы для моего запроса. Поскольку это канал только для чтения в реальном времени из другого отдела, я не могу исправить эти данные, однако я пытаюсь предотвратить проблемы в моем запросе.

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

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

Я тогда подумал, что сделаю первую() агрегатную функцию на всех столбцах, однако это тоже неправильно. Синтаксически я делаю что-то не так?

обновление: Просто хотел отметить: эти записи являются дубликатами на неключевом / неиндексированном поле ID, указанном выше. Идентификатор-это текстовое поле, которое, хотя и имеет то же значение, отличается от других данных, вызывающих проблему.

6 ответов


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

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

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

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

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


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

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 частично заполненные записи и "сливает" данные.

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

попробуй такое

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