2016-06-15 13 views
3

Angenommen ich eine Tabelle von Fahrzeugen haben:Wie kann ich beitreten selektiv

v   color  col3  col4 col5 ..... 
car   red 
train  gray 
plane  white 
car   blue 
bike   black 
(1000 more) 

und eine Tabelle mit Einstufungen:

prio  v  color   class 
1  car  red   C1 
2  car  %    F3 
3  plane %    W1 
4  bike  blue   B4 
5  bike  white   B8 
6  bike  %    O9 

Die Einstufungen Tabelle ist klein, weniger als 100. Nur eine Lookup-Tabelle . Bei Bedarf können wir den Fahrzeugen eine id Säule hinzufügen.

Jetzt möchte ich die Klassifizierung in die Tabelle der Fahrzeuge hinzufügen. Die Anzahl der Reihen in Fahrzeugen darf sich nicht ändern. Das Ergebnis sollte:

v   color class 
car   red  C1 
train  gray 
plane  white W1 
car   blue F3 
bike   black O9 
(1000 more) 

Nun, wenn ich

SELECT vehicles v 
LEFT JOIN classifications c ON v.v LIKE c.v AND v.color LIKE c.color 

bekomme ich doppelte Einträge, weil die Klassifizierung Match nicht eindeutig ist. Zum Beispiel entspricht ein weißes Fahrrad Regel 5 und 6, in diesem Fall muss Regel 5 genommen werden, weil es die niedrigere prio hat.

Wie kann ich die Duplikate vermeiden?

Antwort

3

Sie können dies tun mit einer korrelierten Abfrage und LIMIT:

SELECT v.*, 
     (SELECT c.class FROM classifications c 
     WHERE v.v like c.v AND v.color LIKE c.color 
     ORDER BY c.prio LIMIT 1) AS class 
FROM vehicles v 

Obwohl ich verstehe nicht, warum Sie LIKE verwenden, wenn Sie für die exakten ein Spiel suchen, nehme ich dies schneller sein:

LIKE wird für teilweise Zeichenfolge Vergleich verwendet, und es ist ein echter Leistungskiller! Also vermeide es so gut du kannst.

+0

Vielen Dank, Ihre Lösung scheint es zu tun. Ich wusste nicht, dass ich eine "Auswahl" haben kann, wo eine Spalte benötigt wird. Ich benutze "Gefällt mir", weil ich einen Mustervergleich machen möchte !? Was, wenn ich 2 Spalten aus der Klassifizierungs-Tabelle haben möchte, sagen wir Klasse1 und Klasse? Ich muss die korrelierte Abfrage für eine andere Spalte wiederholen? – jms

+1

Aber Sie sind nicht passendes Muster, Sie verwenden entweder exakte Übereinstimmung, oder entspricht '%', keine Notwendigkeit für 'LIKE' @jms – sagi

0

Wie wäre es mit distinct?

select distinct vehicles v left join classifications c 
on v.v like c.v and v.color like c.color 

ich jetzt nicht versuchen können, aber das sollte genug sein, zu tun, was für Sie ...

+0

Er will die erste Klasse von' prio' bestellt werden – sagi

0

EDIT fragen: Diese Abfrage in den Kommentaren unten nicht wie erklärt wird funktionieren. Ich werde diese Antwort trotzdem für Lernzwecke hinterlassen.


können Sie tun das, group by, having Aggregatfunktionen und die min Funktion:

select * from vehicles v 
      left join classifications c on v.v like c.v and v.color like c.color 
      group by v.v 
      having MIN(prio) 

Dies wird Gruppe die Ergebnisse durch das Fahrzeug und dann die Zeile mit der niedrigsten Priorität wählen.

+0

Es wird es zwingen, einen Datensatz zurückzugeben pro Fahrzeug, aber das Haben geschieht nach der Gruppe durch und unter Verwendung einer Aggregatfunktion dort wird wahrscheinlich merkwürdige Effekte haben. – Kickstart

+0

@Kickstart Da ich das wirklich interessant finde, könntest du das weiter erklären? Welche seltsamen Effekte könnten auftreten? Ich habe die Abfrage mit einem kleinen Beispiel-Datensatz getestet und es hat funktioniert – eol

+0

Es gibt 2 Hauptprobleme. Ihre Anfrage (mit Ausnahme der HAVING-Klausel) wird für jedes Fahrzeug eine Zeile zurückgeben. Welche Zeile es zurückbringt, ist nicht definiert - es könnte die erste Zeile, die letzte Zeile oder irgendeine dazwischen sein, und dies könnte sich in Zukunft ändern. Oft ist es die erste Zeile (nicht die Zeile mit der niedrigsten Nummer, die erste Zeile in der Tabelle), aber das ist eher ein Zufall, wie MySQL Datensätze verarbeitet. Ich habe eine schnelle SQL-Geige eingerichtet, die hoffentlich demonstriert, was passieren kann - http://www.sqlfiddle.com/#!9/d2145/1 - Beachten Sie, dass die 2. zurückgegebene Zeile die höhere a_number für diesen Namen hat – Kickstart

0

SELECT * FROM vehicles v LEFT JOIN classifications c ON c.prio= (SELECT prio FROM classifications c WHERE v.v like c.v AND v.color LIKE c.color ORDER BY c.prio LIMIT 1) Dies setzt voraus, dass "prio" einzigartig ist.

0

Wenn Sie vermeiden möchten, eine korrelierte Unterabfrage zu verwenden (was abhängig von den Daten zu Leistungsproblemen führen kann, da MySQL die Unterabfrage für jede einzelne zurückgegebene Zeile ausführen muss), gibt es noch einige andere Optionen:

Haben Sie eine Sub-Abfrage, die die min Prio für jedes Fahrzeug/Farbe zurück bringt (so diese Unterabfrage wird einmal durchgeführt), und kommen Sie, dass gegen die Einstufungen Tisch, an dem das Fahrzeug, Farbe und Prio min Spiel

SELECT v.v,    
    v.color,  
    c.class 
FROM vehicles v 
LEFT OUTER JOIN 
(
    SELECT v, color, MIN(prio) AS min_prio 
    FROM classifications 
    GROUP BY v, color 
) sub0 
ON v.v = sub0.v AND v.color = sub0.color 
LEFT JOIN classifications c ON sub0.v = c.v AND sub0.color = c.color AND sub0.min_prio = c.prio 

Eine andere Möglichkeit besteht darin, die GROUP_CONCAT-Funktion zu missbrauchen. Dies setzt voraus, dass das Klassenfeld niemals Kommas enthält (wenn Sie dann möglicherweise ein alternatives Trennzeichen verwenden könnten).

SELECT v.v,    
    v.color,  
    SUBSTRING_INDEX(GROUP_CONCAT(c.class ORDER BY prio), ',', 1) AS class 
FROM vehicles v 
LEFT JOIN classifications c ON v.v = c.v AND v.color = c.color 
GROUP BY v.v,    
    v.color 
Verwandte Themen