Kann ich ein berechnetes Feld in einer SELECT-Abfrage wiederverwenden?

76

Gibt es eine Möglichkeit, ein berechnetes Feld in einer MySQL-Anweisung wiederzuverwenden? Ich erhalte die Fehlermeldung "unbekannte Spalte total_sale" für:

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / total_sale as f1_percent
FROM sales s

oder muss ich die Berechnung wiederholen, was zu einer sehr langen SQL-Anweisung führen würde, wenn ich alle erforderlichen Berechnungen hinzufügen würde.

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / (s.f1 + s.f2) as f1_percent
FROM sales s

Natürlich kann ich alle Berechnungen in meinem PHP-Programm durchführen.

sdfor
quelle
"Natürlich kann ich alle Berechnungen in meinem PHP-Programm durchführen" - Das wäre nicht die schlechteste Idee.
Paul Spiegel

Antworten:

83

Ja, Sie können Variablen wiederverwenden. Das ist wie man es macht:

SELECT 
    @total_sale := s.f1 + s.f2 as total_sale, 
    s.f1 / @total_sale as f1_percent
FROM sales s

Lesen Sie hier mehr darüber: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html

[Hinweis: Dieses Verhalten ist undefiniert. Laut den MySQL-Dokumenten:]

In der Regel sollten Sie einer Benutzervariablen niemals einen Wert zuweisen und den Wert in derselben Anweisung lesen. Möglicherweise erhalten Sie die erwarteten Ergebnisse, dies ist jedoch nicht garantiert.

rzetterberg
quelle
@OMG Ponys Lust auszuarbeiten? "@total_sale: =" ist das nicht genug Deklaration?
Rzetterberg
Das setzt die Variable und deklariert sie nicht. Deklarieren bedeutet entweder die Verwendung einer SETAnweisung oder einer abgeleiteten Tabellen- / Inline-Ansicht.
OMG Ponys
2
"Sie können einer Benutzervariablen auch in anderen Anweisungen als SET einen Wert zuweisen. In diesem Fall muss der Zuweisungsoperator: = und nicht = sein, da letzterer als Vergleichsoperator = in Nicht-SET-Anweisungen behandelt wird:"
rzetterberg
13
@OMGPonies (und andere) Dies wird nicht unterstützt: "In der Regel sollten Sie einer Benutzervariablen niemals einen Wert zuweisen und den Wert in derselben Anweisung lesen. Möglicherweise erhalten Sie die erwarteten Ergebnisse, dies ist jedoch nicht garantiert." Es funktioniert wie in, es läuft. Die Ergebnisse sind jedoch möglicherweise nicht korrekt.
Ariel
3
Wenn ich versuche, dies mit einer Gruppenfunktion zu verwenden (z. B. SUModer COUNT, erhalte ich das kontraintuitive und nicht hilfreiche Ergebnis, dass die Variablen immer den Wert der vorherigen Zeile haben, nicht die Zeile, in der ich mich befinde. Sie wird aus gutem Grund nicht unterstützt und sollte es auch sein vermieden.
David Moles
62

Folgendes scheint bei meinen Tests unter MySQL 5.5 gut zu funktionieren:

SELECT 
    s.f1 + s.f2 as total_sale, 
    s.f1 / (SELECT total_sale) as f1_percent
FROM sales s
Robert D.
quelle
5
Ich mag das. Bei weitem die beste Lesbarkeit aller Antworten und keine Warnungen bezüglich der Verwendung in der MySQL-Dokumentation. Es kann jedoch nicht verwendet werden, um Gruppenergebnisse zu referenzieren, wie sie mit SUM oder COUNT erhalten werden.
David
3
Da die aktuell akzeptierte Antwort nicht jedes Mal funktionieren konnte, sollte dies die akzeptierte Antwort sein
Robin Choffardet
1
Ich habe gerade auf MariaDB 10.1.24 Folgendes getestet und es hat perfekt funktioniert. SELECT Price_Per_SqFt, (Price_Per_SqFt / 2) AS col1, (SELECT col1 + 1) AS col2 FROM Items LIMIT 100
Robert D
4
Beachten Sie, dass dies möglicherweise mit einfacher Arithmetik funktioniert, aber nicht mit zB SUModer COUNT: Sie erhaltenreference '[colname]' not supported (reference to group function)
David Moles
Dies scheint auch nicht zu funktionieren, wenn der Spaltenname, den Sie auswählen, den Namen mit einer anderen tatsächlichen Spalte in einer der Tabellen (aus Tabellen oder verbundenen Tabellen) teilt
Brian Leishman
14

Nur plattformübergreifend unterstützte Mittel verwenden eine abgeleitete Tabellen- / Inline-Ansicht:

SELECT x.total_sale,
       x.f1 / x.total_sale as f1_percent
  FROM (SELECT s.f1,
               s.f1 + s.f2 as total_sale, 
          FROM sales s) x
OMG Ponys
quelle
8

Sie können eine Unterauswahl verwenden:

select tbl1.total_sale,
       tbl1.f1/tbl1.total_sale as f1_percent 
  from (select s.f1+s.f2 AS total_sale, 
               s.f1 
          from sales s) as tbl1;
AJ.
quelle
5

Sie können Unterabfragen wie folgt verwenden:

SELECT 
    h.total_sale, 
    s.f1 / h.total_sale AS f1_percent
FROM sales s,
    (SELECT id, f1 + f2 AS total_sale FROM sales) h
WHERE
    s.id = h.id

Bearbeiten:
festes kartesisches Produkt, vorausgesetzt der Primärschlüssel ist id.
Dies sollte nach der Optimierung der Lösung von OMG Ponies entsprechen, aber ich denke, es wird schwieriger zu lesen, wenn Sie mehr Unterabfragen benötigen.

Kiw
quelle
1

Ich habe mir hier verschiedene Antworten angesehen und ein paar Experimente durchgeführt.

Insbesondere verwende ich MariaDB 10.1.

Für eine "einfache" Sache können Sie tun, was Robert D in seinem Kommentar vorgeschlagen hat:

SELECT Price_Per_SqFt, (Price_Per_SqFt/2) AS col1, (SELECT col1 + 1) AS col2 FROM Items 

Wenn Sie eine Art Aggregatfunktion mit einem inneren Join verwenden, können Sie diese nicht verwenden. Sie können diesen Ansatz jedoch wie folgt mit dem inneren Join-Ansatz kombinieren (NB MwSt. = "Umsatzsteuer" ... und NB in ​​Finanzdatenwährung) Felder haben normalerweise 4 Dezimalstellen, ich denke es ist historisch ...)

SELECT 
    invoices.invoiceNo, invoices.clientID, invoices.Date, invoices.Paid, 
  invoicesWithSubtotal.Subtotal,
  ROUND( CAST( Subtotal * invoices.VATRate AS DECIMAL( 10, 4 )), 2 ) AS VAT,
  (SELECT VAT + Subtotal) AS Total
FROM invoices 
    INNER JOIN 
    ( SELECT Sum( invoiceitems.Charge ) AS Subtotal, invoices.InvoiceNo FROM invoices 
        INNER JOIN invoiceitems ON invoices.InvoiceNo = invoiceitems.InvoiceNo
            GROUP BY invoices.InvoiceNo ) invoicesWithSubtotal
    ON invoices.InvoiceNo = invoicesWithSubtotal.InvoiceNo

Ich wollte das oben ViewGesagte verwenden, um Rechnungen mit ihren Zwischensummen, Mehrwertsteuer und Summen aufzulisten. Es stellte sich heraus, dass MariaDB (und mit ziemlicher Sicherheit MySQL) das Verschachteln in der FROMKlausel nicht zulassen . Dies lässt sich jedoch leicht lösen, indem Sie eine erste Viewerstellen, die das InvoiceNound auflistet Subtotal, und dann eine zweite Viewerstellen, die auf die erste verweist. In Bezug auf die Leistung habe ich überhaupt keine Ahnung von dieser Art von Doppelanordnung View.

Mike Nagetier
quelle
0

Ich habe Folgendes getestet und es scheint die ganze Zeit zu funktionieren. Vielleicht gibt es einen Grund dafür, weil ich die Variable @total_sales als Wert und nicht als Zeichenfolge vordefiniert und ihren Typ während der Auswahl nicht neu definiert habe Erklärung ??

Wenn ich folgendes mache

    set @total_sales = 0;

    SELECT 
       @total_sale := s.f1 + s.f2 as total_sale, 
      s.f1 / @total_sale as f1_percent
   FROM sales s
Lawrence Edel
quelle
Das Hauptproblem bei Variablen ist nicht die Eingabe, sondern die Reihenfolge der Ausführung. Im Dokument heißt es: "Anders als in SET-Anweisungen sollten Sie einer Benutzervariablen niemals einen Wert zuweisen und den Wert in derselben Anweisung lesen. Möglicherweise erhalten Sie die erwarteten Ergebnisse, aber dies ist nicht garantiert (...) für die Reihenfolge der Auswertung für Ausdrücke mit Benutzervariablen ist undefiniert. " In Ihrem Beispiel hat @total_sales möglicherweise den richtigen Wert bei der Berechnung von f1_percent, aber möglicherweise auch den Wert der vorhergehenden Zeile.
Eino Gourdin