web-dev-qa-db-ja.com

SQLクエリから重複を削除する(「個別に使用する」だけでなく)

おそらく簡単です、ここに私のクエリがあります:

SELECT DISTINCT U.NAME, P.PIC_ID
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%';

しかし、これは行が同じu.nameとp.pic_idの両方を持つ重複を削除するだけです。名前の重複がある場合は、他の行を除外するようにします。これは奇妙なクエリですが、一般的に、SELECT句の単一の列に個別を適用するにはどうすればよいですか?

13
Dave

最小のPIC_IDを維持することを任意に選択します。また、暗黙的な結合構文の使用を避けてください。

SELECT U.NAME, MIN(P.PIC_ID)
    FROM USERS U
        INNER JOIN POSTINGS P1
            ON U.EMAIL_ID = P1.EMAIL_ID
        INNER JOIN PICTURES P
            ON P1.PIC_ID = P.PIC_ID
    WHERE P.CAPTION LIKE '%car%'
    GROUP BY U.NAME;
18
Joe Stefanelli

あなたの質問はちょっと紛らわしいです。ユーザーごとに1行のみを表示しますか、それとも写真ごとに行を表示し、U.NAMEフィールドの値の繰り返しを抑制しますか? 2番目が欲しいと思います。そうでない場合は、最初の答えがたくさんあります。

繰り返し値を表示するかどうかは、SQLが実際に設計されていない表示ロジックです。ループ内でカーソルを使用して、結果を行ごとに処理できますが、パフォーマンスが大幅に低下します。 .NET言語やJavaのような「スマートな」フロントエンド言語を使用している場合、このデータをどのような構造に組み込んでも、UIに最終的に表示する前に繰り返し値を抑制するように簡単に操作できます。

Microsoft SQL Serverを使用していて、データレイヤーで変換が行われる場合、CTE(計算テーブル式)を使用して初期クエリを保持し、CTEの各行から値を選択することを検討できます。前の行の列は同じデータを保持します。カーソルよりもパフォーマンスは向上しますが、どちらの場合も面倒です。観察する:

USING CTE (Row, Name, PicID)
AS
(
    SELECT ROW_NUMBER() OVER (ORDER BY U.NAME, P.PIC_ID),
       U.NAME, P.PIC_ID
    FROM USERS U
        INNER JOIN POSTINGS P1
            ON U.EMAIL_ID = P1.EMAIL_ID
        INNER JOIN PICTURES P
            ON P1.PIC_ID = P.PIC_ID
    WHERE P.CAPTION LIKE '%car%'
    ORDER BY U.NAME, P.PIC_ID 
)
SELECT
    CASE WHEN current.Name == previous.Name THEN '' ELSE current.Name END,
    current.PicID
FROM CTE current
LEFT OUTER JOIN CTE previous
   ON current.Row = previous.Row + 1
ORDER BY current.Row

上記のサンプルはTSQL固有のものです。 PL/SQLのような他のDBPLで動作することは保証されていませんが、ほとんどのエンタープライズレベルのSQLエンジンには同様のものがあると思います。

2
KeithS

MINまたはMAXが他の列に選択する値をクエリに伝える必要があります。

 SELECT
   U.NAME, MIN(P.PIC_ID)
 FROM
   USERS U,
   PICTURES P,
   POSTINGS P1
 WHERE
   U.EMAIL_ID = P1.EMAIL_ID AND
   P1.PIC_ID = P.PIC_ID AND
   P.CAPTION LIKE '%car%'
 GROUP BY
   U.NAME;
1
Brandon Horsley

私があなたを正しく理解している場合は、1つの列のみの重複を除外して、サブセレクトへの内部結合をリストしたい

select u.* [whatever joined values]
from users u
inner join
(select name from users group by name having count(*)=1) uniquenames
on uniquenames.name = u.name
1
Xhalent

私があなたを正しく理解していれば、同じ名前(およびそれらの異なるID)を持つすべての写真のリストが必要です。これでうまくいくと思います:

SELECT U.NAME, P.PIC_ID
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND U.Name IN (
SELECT U.Name 
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%';
GROUP BY U.Name HAVING COUNT(U.Name) > 1)

まだ実行していないので、構文エラーが1つまたは2つある可能性があります。

0