programing

SQL Left Join 첫 번째 일치 항목만

cafebook 2023. 4. 28. 21:30
반응형

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

(약 24개의 열 및 10K 행)

저의 첫 번째 본능은 제게 약 80,000개의 행을 제공하는 것이었습니다.

SELECT DISTINCT P.IDNo
FROM people P

그러나 다음을 시도하면 모든 행이 반환됩니다.

SELECT DISTINCT P.*
FROM people P

OR

SELECT 
    DISTINCT(P.IDNo) AS IDNoUnq 
    ,P.FirstName
    ,P.LastName
    ...etc.    
FROM people P

그리고 나서 저는 모든 열에 FIRST() 집계 기능을 수행할 것이라고 생각했는데, 그것도 잘못된 것 같습니다.제가 여기서 뭘 잘못하고 있는 건가요?

업데이트: 참고 사항:이러한 레코드는 위에 나열된 키가 아닌/색인되지 않은 ID 필드를 기준으로 중복됩니다.ID는 동일한 값을 가지지만 문제를 일으키는 다른 데이터와 다른 경우인 텍스트 필드입니다.

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

ID 열 추가(사용자)ID)를 선택한 다음 상관된 하위 쿼리를 사용하여 각 값의 첫 번째 값을 반환합니다.

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

신중하게 고려한 후에 이 딜마는 몇 가지 다른 해결책을 가지고 있습니다.

Aggregate Everything 각 열의 Aggregate를 사용하여 가장 크거나 가장 작은 필드 값을 가져옵니다.이것은 부분적으로 작성된 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 
    x.*,
    c.*
from 
    x
Cross Apply 
    (
        Select 
            Top (1)
            IDNo,
            FirstName,
            LastName,
            ...., 
        from 
            people As p
        where 
            p.idno = x.idno
        Order By 
            p.idno //unnecessary if you don't need a specific match based on order
    ) As c

교차 적용은 내부 결합처럼 작동하고 외부 적용은 왼쪽 결합처럼 작동합니다.

SQL Server 크로스 적용 및 외부 적용

제가 잘못한 것으로 드러났습니다. 중요한 열 중에서 먼저 중첩된 선택을 수행하고, '고유한' 데이터의 휴지통 열이 좋은 데이터를 손상시키지 않도록 별도의 선택을 수행해야 했습니다.다음은 문제를 해결한 것으로 보입니다...나중에 전체 데이터 세트를 착용해 보겠습니다.

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

사용해 보세요.

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

중복 행의 특성에 따라 해당 열에 대소문자를 구분하는 것이 좋습니다.이 열에서 데이터 정렬을 설정하려면 다음 작업을 수행해야 합니다.

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

언급URL : https://stackoverflow.com/questions/19825142/sql-left-join-first-match-only

반응형