2011-02-03 14 views
9

è probabilmente semplice, ecco la mia domanda:rimozione dei duplicati da una query SQL (non solo "usare distinta")

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

ma questo sarà solo rimuovere i duplicati, dove una fila ha sia la stessa u.name e p.pic_id. Lo voglio così se ci sono duplicati dei nomi, lascia solo le altre righe. È una query strana, ma in generale, come posso applicare il distinto a una singola colonna della clausola SELECT?

+1

quale dei multipli P.PIC_ID vuoi con il singolo U.NAME? –

risposta

15

Scegliere arbitrariamente di mantenere il PIC_ID minimo. Inoltre, evitare di utilizzare la sintassi di join implicita.

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

A seconda del caso aziendale, è possibile utilizzare MIN o MAX (ovviamente non entrambi allo stesso tempo). – Naufal

1

È necessario indicare alla query quale valore selezionare per le altre colonne, MIN o MAX sembrano scelte appropriate.

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

Non penso che questo sia ciò che vuole. Penso che lui desideri tutte le immagini, ma nei casi in cui un utente ha diverse foto non vuole che il nome dell'utente venga ripetuto nell'elenco. – KeithS

+1

Non incoraggiare l'uso della sintassi di join implicita. Se gli stai mostrando come fare le cose, mostragli come fare le cose correttamente. – HLGEM

+0

@HLGEM, per quanto ne so, cosa c'è di sbagliato nella sintassi implicita? Alcuni driver ODBC (come D3 di tigerlogic) supportano solo la sintassi implicita. –

0

Se ho capito bene, si desidera un elenco di tutte le immagini con lo stesso nome (e le loro differenti IDS) in modo tale che il loro nome si verifica più di una volta nella tabella. Penso che questo farà il trucco:

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) 

non l'ho eseguito, quindi ci può essere un errore di sintassi o due lì.

+1

Non incoraggiare l'uso della sintassi di join implicita. Se gli stai mostrando come fare le cose, mostragli come fare le cose correttamente. – HLGEM

+0

L'ho considerato, ma volevo risolvere il problema su cui stava lavorando. –

1

Se ho capito bene, si desidera elencare per escludere i duplicati su una sola colonna, join interno ad un sub-select

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 
2

La tua domanda è una specie di confusione; vuoi mostrare solo una riga per utente o vuoi mostrare una riga per immagine ma sopprimere i valori ripetuti nel campo U.NAME? Penso che tu voglia il secondo; se non ci sono molte risposte per il primo.

Se visualizzare valori ripetitivi è la logica di visualizzazione, per la quale SQL non è stato progettato. Puoi usare un cursore in un ciclo per elaborare i risultati riga per riga, ma perderai molte prestazioni. Se si dispone di un linguaggio di interfaccia "intelligente" come un linguaggio .NET o Java, qualunque costruzione venga inserita in questi dati può essere manipolata a basso costo per sopprimere i valori ripetuti prima di visualizzarli infine nell'interfaccia utente.

Se si utilizza Microsoft SQL Server e la trasformazione deve essere eseguita sul livello dati, è possibile utilizzare un CTE (espressione della tabella calcolata) per contenere la query iniziale, quindi selezionare i valori da ciascuna riga del CTE in base al fatto che le colonne nella riga precedente mantengano gli stessi dati. Sarà più performante del cursore, ma sarà comunque un po 'disordinato. Osservare:

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 

Il campione sopra riportato è specifico per TSQL; non è garantito il funzionamento in nessun altro DBPL come PL/SQL, ma penso che la maggior parte dei motori SQL di livello enterprise abbiano qualcosa di simile.