2012-04-10 4 views
5

Hier ist meine Tabelle und die darin enthaltenen Daten:Was passiert bei der Verwendung von 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 | 
+-----------+----------+----------+ 

Meine Absicht ist es, die Liste der third_id s von data Feld bestellt zu bekommen. Jetzt habe ich die folgende Abfrage ausgeführt.

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

Und ich bekomme das folgende Ergebnis wie erwartet.

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

Die folgende Abfrage funktioniert auch wie erwartet.

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

mit Ausgang

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

Dann lief ich die folgenden.

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

Aber hier bekomme ich ein unerwartetes Ergebnis:

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

Hier 3 müssen nach 2 und 4, da ich auf dem data Feld bin der Bestellung. Was mache ich falsch? Oder muss ich eine andere Strategie wählen?

Hinweis: Dieses Szenario passiert bei meinem Projekt. Die hier bereitgestellten Tabellen gehören nicht zur ursprünglichen Datenbank. Es ist von mir erstellt, um das Problem zu erklären. Originaltabellen enthalten Tausende von Zeilen. ich Datenbank-Dump bin Einfügen, wenn Sie mit den Daten experimentieren möchten:

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

"Aber, hier bekomme ich ein unerwartetes Ergebnis:" - Das ist nicht unerwartet. –

+0

@MitchWheat Aber wie? – Jomoos

+1

Wenn ich sql wäre, würde ich diese 'ORDER BY'-Klausel ablehnen, aber' mysql' ist dafür notorisch tolerant. Mit welchen Daten möchten Sie bestellen? –

Antwort

3

Sie wollen wahrscheinlich etwas wie

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

tun, die min(data) oder max(data) oder was auch immer ist.

+0

Die Verwendung von 'min (data)' hat die Arbeit getan. Obwohl die Antwort von @Devart auch funktioniert, akzeptiere ich diese Antwort, weil es eine natürlichere und einfachere Lösung scheint. – Jomoos

+1

Habe gerade nachgeschaut. Schätze beide sollten funktionieren, obwohl ich sagen würde @ Devarts ist ein bisschen zerbrechlich. Theoretisch ist Ihre Ausgabe ungeordnet, wenn Sie keine ORDER BY haben, obwohl diese Theorie oft von der Praxis abweicht. –

2

Das Ausführen einer SELECT DISTINCT erfordert, dass die Datenbank die Werte in den Spalten sortiert, da dies der effizienteste Weg ist, um die verschiedenen Werte zu finden. Soweit ich weiß ORDER BY Klauseln, die keine Spalten enthalten, die in der Abfrage ausgegeben werden, werden nicht geehrt (SQL SERVER wird die Abfrage nicht akzeptieren), da es nicht klar ist, was es bedeuten würde, durch etwas zu bestellen, das nicht sich beteiligen.

+0

Ich sehe keinen Grund, 'ORDER BY' zu ignorieren, nur weil es nicht ausgewählt ist. Das Problem ist hier die Mehrdeutigkeit. –

+0

In mysql, SELECT DISTINCT nicht die Werte, sagt [hier] (http://www.mysqlfaqs.net/mysql-faqs/SQL-Statements/Select-Statement/How-does-DISTINCT-work-in- MySQL) – fqsxr

+0

Es ist eine Eigenart von MySQL, dass Sie diese Abfrage schreiben können, da es keinen Sinn macht. In der 'SELECT DISTINCT' ignorieren Sie vollständig alle Informationen in Bezug auf 'Daten'. Die Abfrage-Engine sollte Ihnen sagen, dass Sie keine vernünftige Frage stellen und bombardieren. Stattdessen wählt es Menschen zu verwirren. – briantyler

2

Sie können eine Unterabfrage verwenden -

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; 

Es wird dazu beitragen, auszuwählen und zu sortieren zunächst alle Daten, dann verschiedene Werte auszuwählen.

1

Ich hatte dieses genaue Problem zuvor. Ich kam schließlich mit einer einfachen Lösung, scheint fast zu einfach. Sie müssen eine Unterabfrage als Spalte der ausgewählten Abfrage verwenden. In dieser Unterabfrage werden Sie nach Datum sortieren. Wenn Sie alles in einer einzigen Abfrage mit ORDER BY vor dem JOIN tun. Sie möchten zuerst bestellen, also gehen Sie mit der Unterabfrage. http://nathansnoggin.blogspot.com/2009/04/select-distinct-with-order-by.html