2011-12-22 7 views
7

Sto tentando di creare una query (sqlite) che eseguirà un GROUP BY ma non raggrupperà nulla con il valore 'unknown'. Per esempio, io ho il tavolo:tranne che per determinati valori

id | name | parent_id | school_id | 
1 | john | 1  | 1  | 
2 | john | 1  | 1  | 
3 | john | 1  | 1  | 
4 | nick | 2  | 2  | 
5 | nick | 2  | 2  | 
6 | nick | 3  | 3  | 
7 | bob  | 4  | 4  | 
8 | unknown | 5  | 5  | 
9 | unknown | 5  | 5  | 
10| unknown | 5  | 5  | 

Con la corretta query con 'gruppo per nome, parent_id, school_id' ho bisogno dei seguenti righe restituite:

id | name | parent_id | school_id | 
1 | john | 1  | 1  | 
3 | nick | 2  | 2  | 
4 | nick | 3  | 3  | 
5 | bob  | 4  | 4  | 
6 | unknown | 5  | 5  | 
7 | unknown | 5  | 5  | 
8 | unknown | 5  | 5  | 

Qualsiasi aiuto sarebbe molto apprezzato. Grazie!

+0

Risposta aggiunta evitando GROUP BY e il costo di analizzare la tabella due volte. – MatBailie

risposta

7

Non si può facilmente farlo con una sola affermazione, ma si può UNION i risultati di due dichiarazioni

  • GROUP l'elenco di tutte maunknown
  • Add (UNION) l'elenco di tutti i unknown

SQL Statement

SELECT MIN(id), name, parent_id, school_id 
FROM YourTable 
WHERE name <> 'unknown' 
GROUP BY 
     name, parent_id, school_id 
UNION ALL 
SELECT id, name, parent_id, school_id 
FROM YourTable 
WHERE name = 'unknown' 

Nota che io ti assumo hanno inviato sbagliato unknown id nel vostro risultato

+0

Assolutamente geniale !! – Rahul

+0

@Rahul - stampato e incorniciato sul muro :) –

+0

Perfetto ... grazie! – Nick

1
SELECT MIN(id), name, parent_id, school_id 
    FROM Table 
WHERE name <> 'unknown' 
GROUP BY name, parent_id, school_id 
UNION ALL 
SELECT id, name, parent_id, school_id 
    FROM Table 
WHERE name = 'unknown' 
+0

+1 La stessa idea sembra. –

+0

sì ... ma mi piace la tua risposta ... hai spiegato a Nick come andare sulla query :) – Akhil

1
SELECT 
    MIN(id) AS id, 
    IF(tmpname=id,"unknown",tmpname) AS name, 
    parent_id, 
    school_id 
FROM (
    SELECT 
    id,parent_id,school_id 
    IF(name="unknown",id,name) AS tmpname 
    FROM <tablename> 
) AS baseview 
GROUP BY tmpname 
+0

+1 intrigante ma dovresti raggruppare su parent_id e school_id e non puoi a mia conoscenza controllare per 'tmpname = id' nella tua selezione esterna. –

+0

Dovrebbe essere tmpid allo stesso modo di tmpname - sorry –

+1

@Lievent - D'accordo, è necessario aggiungere quei due campi a GROUP BY, quindi modificare 'id' nel primo blocco IF() in' MIN (id) '. Invierei anche espressamente il numero intero a un varchar(), in modo da evitare l'ambiguità e la possibilità che provi a lanciare il varchar() su un numero intero. [In entrambi i blocchi IF().] – MatBailie

2

Come una singola query ...

SELECT 
    MIN(id)   AS id, 
    name, 
    parent_id, 
    school_id 
FROM 
    yourTable 
GROUP BY 
    CASE WHEN name = 'unknown' THEN id ELSE 0 END, 
    name, 
    parent_id, 
    school_id 

O forse ..

GROUP BY 
    CASE WHEN name <> 'unknown' THEN name ELSE CAST(id AS VARCHAR(???)) END, 
    parent_id, 
    school_id 

-- Where VARCHAR(???) is the data type of the `name` field. 
-- Also assumes no value in `name` is the same as an id for an 'unknown' field 

Entrambi evitano UNION e il sovraccarico di analizzare il tavolo due volte, sostituendolo con una complessità leggermente aumentata GROUP BY.

+0

+1 Afaik, funzionerebbe in SQL Server ma SQLLite lo consente? –

+0

@Lieven - Non so tbh, sarebbe necessario testare. Diversamente dalle discrepanze di sintassi, ciò non infrange nulla secondo ANSI SQL. Spero che funzioni, non è una domanda complessa ... – MatBailie

+0

Non complesso ma non qualcosa che viene subito in mente. Non sono sicuro del costo: l'UNION * può * usare gli indici mentre CASE è una scansione completa della tabella. L'OP dovrebbe confrontare i piani di esecuzione per verificare quale sia la migliore. –

Problemi correlati