web-dev-qa-db-ja.com

SQL左結合の最初の一致のみ

多数の結合を持つ多数の大きなテーブル(行と列)に対してクエリを実行していますが、テーブルの1つに重複したデータ行があり、クエリに問題が発生しています。これは別の部門からの読み取り専用のリアルタイムフィードであるため、そのデータを修正することはできませんが、クエリからの問題を防止しようとしています。

それを考えると、このクラップデータを左の結合として適切なクエリに追加する必要があります。データセットは次のようになります。

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ダースの列と10万行)

私の最初の本能は、約80K行を与えた個別の実行です。

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はテキストフィールドであり、値は同じですが、問題の原因となっている他のデータとは異なるケースです。

37
Dave

間違ったことをしていましたが、重要な列だけで最初にネストされた選択を実行し、「ユニークな」データのゴミの列が私の良いデータを破損しないように明確な選択を行う必要がありました。以下は問題を解決したように見えます...しかし、私は後で完全なデータセットで試みます。

SELECT DISTINCT P2.*
FROM (
  SELECT
      IDNo
    , FirstName
    , LastName
  FROM people P
) P2

要求されたプレイデータを次に示します。 http://sqlfiddle.com/#!3/050e0d/

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
Dave

distinctnot関数です。常に選択リストのall列で動作します。

あなたの問題は、ウィンドウ関数を使用して簡単に解決できる典型的な「グループごとの最大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 ...
39

ID列(PeopleID)を追加し、相関サブクエリを使用して各値の最初の値を返します。

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

重複行の性質によっては、必要なのはそれらの列で大文字と小文字を区別することだけのように見えます。これらの列に照合順序を設定すると、次のようになります。

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

2
Fiddles

慎重に検討した後、このディレマにはいくつかの異なる解決策があります。

Aggregate 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

Get First(またはLast record)

http://sqlfiddle.com/#!3/59cde/2

-- ------------------------------------------------------
-- 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
1
Dave

これを試して

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