2012-04-10 2 views
5

Ecco la mia tabella e dei dati in esso contenuti:Cosa sta succedendo quando si usa DISTINCT?

Table: first 

+----------+------+ 
| first_id | data | 
+----------+------+ 
|  1 | 5 | 
|  2 | 6 | 
|  3 | 7 | 
|  4 | 6 | 
|  5 | 7 | 
|  6 | 5 | 
|  7 | 7 | 
|  8 | 6 | 
|  9 | 5 | 
|  10 | 7 | 
+----------+------+ 

Table: second 
+-----------+----------+----------+ 
| second_id | first_id | third_id | 
+-----------+----------+----------+ 
|   1 |  1 |  2 | 
|   2 |  2 |  3 | 
|   3 |  3 |  4 | 
|   4 |  4 |  2 | 
|   5 |  5 |  3 | 
|   6 |  6 |  4 | 
|   7 |  7 |  2 | 
|   8 |  8 |  2 | 
|   9 |  9 |  4 | 
|  10 |  10 |  4 | 
+-----------+----------+----------+ 

La mia intenzione è quella di ottenere l'elenco di third_id s in ordine di data campo. Ora, ho eseguito la seguente query per questo.

SELECT 
    third_id, data 
FROM 
    first f JOIN second s ON (s.first_id = f.first_id) 
ORDER BY 
    data ASC; 

E ottengo il seguente risultato come previsto.

+----------+------+ 
| third_id | data | 
+----------+------+ 
|  4 | 5 | 
|  2 | 5 | 
|  4 | 5 | 
|  2 | 6 | 
|  3 | 6 | 
|  2 | 6 | 
|  2 | 7 | 
|  4 | 7 | 
|  4 | 7 | 
|  3 | 7 | 
+----------+------+ 

La seguente query funziona anche come previsto.

SELECT 
    third_id 
FROM 
    first f JOIN second s ON (s.first_id = f.first_id) 
ORDER BY 
    data ASC; 

con uscita

+----------+ 
| third_id | 
+----------+ 
|  4 | 
|  2 | 
|  4 | 
|  2 | 
|  3 | 
|  2 | 
|  2 | 
|  4 | 
|  4 | 
|  3 | 
+----------+ 

Poi ho eseguito il seguente.

SELECT DISTINCT 
    third_id 
FROM 
    first f JOIN second s ON (s.first_id = f.first_id) 
ORDER BY 
    data ASC; 

Ma, qui ottengo un risultato inaspettato:

+----------+ 
| third_id | 
+----------+ 
|  2 | 
|  3 | 
|  4 | 
+----------+ 

Qui, 3 deve essere dopo 2 e 4, dal momento che ordino sul campo data. Che cosa sto facendo di sbagliato? O devo andare per una strategia diversa.

Nota: Questo scenario si verifica sul mio progetto. Le tabelle fornite qui non appartengono al database originale. È stato creato da me per spiegare il problema. Le tabelle originali contengono migliaia di righe. mi inserisco dump del database se si desidera sperimentare con i dati:

-- 
-- Table structure for table `first` 
-- 

CREATE TABLE IF NOT EXISTS `first` (
    `first_id` int(11) NOT NULL AUTO_INCREMENT, 
    `data` int(11) NOT NULL, 
    PRIMARY KEY (`first_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; 

-- 
-- Dumping data for table `first` 
-- 

INSERT INTO `first` (`first_id`, `data`) VALUES 
(1, 5), 
(2, 6), 
(3, 7), 
(4, 6), 
(5, 7), 
(6, 5), 
(7, 7), 
(8, 6), 
(9, 5), 
(10, 7); 
-- 
-- Table structure for table `second` 
-- 

CREATE TABLE IF NOT EXISTS `second` (
    `second_id` int(11) NOT NULL AUTO_INCREMENT, 
    `first_id` int(11) NOT NULL, 
    `third_id` int(11) NOT NULL, 
    PRIMARY KEY (`second_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; 

-- 
-- Dumping data for table `second` 
-- 

INSERT INTO `second` (`second_id`, `first_id`, `third_id`) VALUES 
(1, 1, 2), 
(2, 2, 3), 
(3, 3, 4), 
(4, 4, 2), 
(5, 5, 3), 
(6, 6, 4), 
(7, 7, 2), 
(8, 8, 2), 
(9, 9, 4), 
(10, 10, 4); 
+4

"Ma, qui ottengo un risultato inaspettato:" - Questo non è inaspettato. –

+0

@MitchWheat Ma come? – Jomoos

+1

Se fossi sql, rifiuterei questa clausola 'ORDER BY', ma' mysql' è notoriamente tollerante. Con quale 'dati' vuoi ordinare? –

risposta

3

Probabilmente si vuole fare qualcosa di simile

SELECT third_id 
FROM first JOIN second USING (first_id) 
GROUP BY third_id 
ORDER BY aggregatesomething(data) 

che è min(data) o max(data) o qualsiasi altra cosa.

+0

L'uso di 'min (data)' ha funzionato. Anche se la risposta di @Devart ha funzionato, accetto questa risposta perché sembra una soluzione più naturale e più semplice. – Jomoos

+1

Ho appena controllato. Suppongo che entrambi dovrebbero funzionare, anche se direi che Devart è un po 'fragile. In teoria, se non si dispone di "ORDER BY", l'output non è ordinato anche se questa teoria differisce spesso dalla pratica. –

2

Fare un SELECT DISTINCT richiede al database di ordinare i valori nelle colonne in quanto è il modo più efficace per trovare i valori distinti. Per quanto a mia conoscenza le clausole ORDER BY che non contengono colonne emesse nella query non vengono onorate (SQL SERVER non accetta la query) in quanto non è chiaro cosa significherebbe ordinare da qualcosa che non partecipare.

+0

Non vedo alcun motivo per ignorare 'ORDER BY' solo perché non è selezionato. Il problema qui è l'ambiguità. –

+0

In mysql, SELECT DISTINCT non ordina i valori, dice [qui] (http://www.mysqlfaqs.net/mysql-faqs/SQL-Statements/Select-Statement/How-does-DISTINCT-work-in- MySQL) – fqsxr

+0

È una stranezza di MySQL che ti consente di scrivere quella query perché non ha senso. In "SELECT DISTINCT" ignori completamente tutte le informazioni relative a 'data'. Il motore delle query dovrebbe dirti che non stai facendo una domanda ragionevole e bombardare. Invece, sceglie di confondere le persone. – briantyler

2

è possibile utilizzare un subquery -

SELECT DISTINCT third_id FROM (
    SELECT 
    third_id 
    FROM 
    first f JOIN second s ON (s.first_id = f.first_id) 
    ORDER BY 
    data ASC 
) t; 

Esso contribuirà a selezionare e ordinare tutti i dati in primo luogo, quindi per selezionare valori distinti.

1

Ho avuto questo problema esatto prima. Alla fine ho trovato una soluzione semplice, sembra quasi troppo semplice. È necessario utilizzare una sottoquery come colonna della query di selezione. In quella subquery si esegue l'ordinamento per data. Quando lo fai tutto in una singola query con ORDER BY, accade prima del JOIN. Vuoi prima ordinare, quindi vai con la sottoquery. http://nathansnoggin.blogspot.com/2009/04/select-distinct-with-order-by.html