2008-10-15 8 views
53

In MySQL 5.0 warum tritt der folgende Fehler beim Versuch, eine Sicht mit einer Unterabfrage in der FROM-Klausel zu erstellen?MySQL: View mit Unterabfrage in der FROM-Klausel Einschränkung

ERROR 1349 (HY000): Blick SELECT enthält eine Unterabfrage in der FROM-Klausel

Wenn dies eine Einschränkung des MySQL-Engine ist, dann, warum sie diese Funktion nicht noch umgesetzt?

Auch, was sind einige gute Problemumgehungen für diese Einschränkung?

Gibt es Problemumgehungen, die für jede Unterabfrage in der FROM-Klausel funktionieren, oder gibt es einige Abfragen, die nicht ausgedrückt werden können, ohne eine Unterabfrage in der FROM-Klausel zu verwenden?


Ein Beispiel query (wurde in einem Kommentar begraben):

SELECT temp.UserName 
FROM (SELECT u1.name as UserName, COUNT(m1.UserFromId) as SentCount 
     FROM Message m1, User u1 
     WHERE u1.uid = m1.UserFromId 
     Group BY u1.name HAVING SentCount > 3) as temp 
+0

Vielen Dank für diesen Beitrag. Ich vermeide in der Regel Ansichten in MySQL. An einem Randfall arbeiten, versuchen, fk Tabellen zu vereinigen - sie in eine Ansicht shoehorning. Jetzt das. Was für ein Schmerz - all diese Einschränkungen bei Unterabfragen? Bereit für einen anderen Motor. – eggmatters

Antwort

17

kann nicht die Abfrage in Ihrem Kommentar sein neu geschrieben werden nur geschrieben werden wie:

SELECT u1.name as UserName from Message m1, User u1 
    WHERE u1.uid = m1.UserFromID GROUP BY u1.name HAVING count(m1.UserFromId)>3 

, die auch mit den bekannten Geschwindigkeitsproblemen mit Unterabfragen in MySQL

+0

Danke, ich wusste nicht, dass Sie die GROUP BY ausführen können, ohne die Aggregatfunktion in SELECT zu haben. Einer der Gründe, warum sie Unterabfragen in der FROM-Klausel in MySQL nicht zulassen, liegt an Geschwindigkeitsproblemen. – Daniel

+0

Es ist nicht unbedingt wegen der Geschwindigkeit in diesem speziellen Fall. Wie es jetzt ist, funktioniert der Optimierer bei Unterabfragen überhaupt nicht gut. Bleib weg von ihnen wenn möglich. Dies ist in 6.0 behoben und eine Menge Fortschritte wurden gemacht, aber das ist in 6.0 und Sie verwenden 5.0. –

+1

Bitte verwenden Sie keine implizite Syntax. Es ist ein SQL-Antipattern und wurde vor 20 Jahren durch eine bessere Syntax repolatisiert. – HLGEM

5

Es scheint ein bekanntes Problem zu sein. werden kann (links außen) verbindet und eine (nicht) NULL irgendeine Art

http://dev.mysql.com/doc/refman/5.1/en/unnamed-views.html

http://bugs.mysql.com/bug.php?id=16757

Viele in Abfragen neu geschrieben. zum Beispiel

SELECT * FROM FOO WHERE ID IN (SELECT ID FROM FOO2) 

als

SELECT FOO.* FROM FOO JOIN FOO2 ON FOO.ID=FOO2.ID 

oder

SELECT * FROM FOO WHERE ID NOT IN (SELECT ID FROM FOO2) 

kann

SELECT FOO.* FROM FOO 
LEFT OUTER JOIN FOO2 
ON FOO.ID=FOO2.ID WHERE FOO.ID IS NULL 
+0

Aber wie würden Sie eine Abfrage in der FROM-Klausel umschreiben? Zum Beispiel, wie könnte ich diese Abfrage neu schreiben ?: SELECT temp.UserName FROM ( SELECT u1.name wie Username, COUNT (m1.UserFromId) als SentCount FROM Nachricht m1, Benutzer u1 WHERE u1.uid = m1. UserFromId Gruppe BY u1.name HABEN SentCount> 3 ) als temp – Daniel

+0

Ich glaube nicht, dass Sie können, aber Sie können eine zweite Ansicht erstellen und wählen Sie aus, anstatt die Unterauswahl zu verwenden, soweit ich weiß. Wenn es Ihnen nichts ausmacht, ein gespeichertes Proc zu verwenden, können Sie auch temporäre Tabellen verwenden (unter der Annahme, dass die letzte Version von MySQL ausreichend ist). – Nikki9696

+0

Oder, wie ich bemerkt habe, kann Grants Lösung für Sie arbeiten. – Nikki9696

74

hatte ich das gleiche Problem helfen sollen. Ich wollte einen Blick zeigen Information des letzten Jahres aus einer Tabelle mit Datensätzen von 2009 auf 2011. Hier ist die ursprüngliche Abfrage erstellen:

SELECT a.* 
FROM a 
JOIN ( 
    SELECT a.alias, MAX(a.year) as max_year 
    FROM a 
    GROUP BY a.alias 
) b 
ON a.alias=b.alias and a.year=b.max_year 

Gliederung der Lösung:

  1. erstellen Ansicht für jede Unterabfrage

Hier ist die Lösung Abfrage Unterabfragen mit diesen Ansichten ersetzen:

CREATE VIEW v_max_year AS 
    SELECT alias, MAX(year) as max_year 
    FROM a 
    GROUP BY a.alias; 

CREATE VIEW v_latest_info AS 
    SELECT a.* 
    FROM a 
    JOIN v_max_year b 
    ON a.alias=b.alias and a.year=b.max_year; 

Es funktioniert gut auf mysql 5.0.45, ohne viel Geschwindigkeitsbegrenzung (im Vergleich zur Ausführung die ursprüngliche Unterabfrage ohne Ansichten auswählen).

+4

fail on backup, da mysql die Sichten basierend auf ihren Namen wiederherstellt, so wird zuerst versucht, "v_latest_info" wiederherzustellen und wird fehlschlagen, weil "v_max_year" noch nicht existiert ... – Apolo

+0

Die Erstellung dieser multiplen Sichten führt zu Leistungsproblemen ? – Annie

+0

Dies sollte als Antwort markiert werden. – enchance

3

erstellen Sie eine Ansicht für jede Unterabfrage ist der Weg zu gehen. Hat es funktioniert wie ein Charme.

4

Sie können dies umgehen, indem Sie eine separate VIEW für jede Unterabfrage erstellen, die Sie verwenden möchten, und dann an der VIEW, die Sie erstellen, mitmachen. Hier ist ein Beispiel: http://blog.gruffdavies.com/2015/01/25/a-neat-mysql-hack-to-create-a-view-with-subquery-in-the-from-clause/

Das ist ganz praktisch, da Sie sehr wahrscheinlich es sowieso wollen würden wieder zu verwenden und helfen Sie, Ihre SQL trocken zu halten.

+0

Hallo Ninjabber - bitte teilen Sie eine bestimmte Sichtweise, die Sie erlebt haben. Ansichten sind sehr mächtig in MySQL, aber ja, Sie müssen ihre Ins und Outs kennen, um Performance-Probleme zu vermeiden, aber meiner Erfahrung nach sind sie leicht vermeidbar. – Gruff

+1

nicht in mysql 5.0 Ich habe Angst. Haben Sie keine Instanz mit 5.0, sondern erstellen Sie eine Instanz, fügen Sie 3 Unterabfragen in Ansichten ein und verknüpfen Sie sie mit indizierten Spalten. Sie werden von dem Erklärungs-Plan überrascht sein. Mit wirklich ausgefeilten Sub-Abfragen, die individuell gut funktionierten, hatte ich schon in 5.6 Probleme. 5,7 ist anders. Dort ist die Handhabung mehr oracle-ish – ninjabber

+1

vergessen hinzuzufügen: Aktualisieren Sie Ihre Maschine auf 5,7 und es gibt keine Einschränkungen. Sogar AWS hat die Unterstützung von 5.7 auf RDS angekündigt. Der einzige Grund, warum Sie nicht upgraden möchten, ist, wenn Sie einen App-Server (sagen wir Hybris) verwenden, der 5.7 noch nicht unterstützt. Aber das ist eine Frage der Zeit, denn 5.7 ist nur auf einer anderen Ebene und bei weitem die beste Engine, die MySQL jemals hatte. Am wichtigsten ist, dass wir endlich mehr als einen Kern verwenden und parallele Transaktionen verarbeiten können, was wiederum erlaubt, mit dem Cache zu spielen und seine Vorteile zu nutzen. – ninjabber