ericag3
Goto Top

Zwei Selects in einem Select berechnen und verrechnen

Wieso funktioniert folgender Select nicht? Es kann nur eine Kleinigkeit sein... Danke!

select eins / zwei

from

(select count(*) as eins from tabelle where 'Kanten SOLL' = 'Kanten IST' and 'Kanten SOLL' between '29.07.2013' and '02.08.2013'),

(select count(*) as zwei from tabelle where 'Kanten SOLL' between '29.07.2013' and '02.08.2013');

Fehlertext:
Meldung 102, Ebene 15, Status 1, Zeile 6
Falsche Syntax in der Nähe von ','.


(Microsoft SQL)

Content-ID: 214137

Url: https://administrator.de/contentid/214137

Ausgedruckt am: 26.11.2024 um 08:11 Uhr

AndreasHoster
AndreasHoster 13.08.2013 aktualisiert um 11:21:32 Uhr
Goto Top
Abgesehen davon, daß ich bei Spaltennamen mit Leerzeichen graue Haare bekomme und der SQL Server ein Datum vermutlich in einem anderen Format haben will, fangen wir doch mal mit den Grundlagen der Fehlersuche an:

Wenn ein verknüpftes Statement nicht tut, verifiziert man zuerst einmal, ob die zugrundeliegenden Statements funktionieren.
D.h. funktionieren die Selects einzeln? Und tun Sie das, was sie sollen?
select count(*) as eins from tabelle where 'Kanten SOLL' = 'Kanten IST' and 'Kanten SOLL' between '29.07.2013' and '02.08.2013'
und
select count(*) as zwei from tabelle where 'Kanten SOLL' between '29.07.2013' and '02.08.2013'

Und wenn Sie nicht tun, vereinfacht man das Statement, um zu sehen wo der Fehler liegt.
Also was macht:
select count(*) as eins from tabelle where 'Kanten SOLL' = 'Kanten IST'
und könnte das Ergebnis stimmen?

Und was das Datumsformat angeht, aus dem Technet:
Wir empfehlen, Datums- und Zeitformate zu verwenden, die nicht von DATEFORMAT abhängen und mehrere Sprachen unterstützen. Die ISO 8601-Formate "1998-02-23T14:23:05" und "1998-02-23T14:23:05 -08:00" sind die einzigen Formate, die als internationaler Standard gelten. Sie sind nicht von DATEFORMAT oder der bei der Anmeldung angegebenen Standardsprache abhängig und unterstützen mehrere Sprachen.
LianenSchwinger
LianenSchwinger 13.08.2013 aktualisiert um 11:28:52 Uhr
Goto Top
Hallo,

unabhängig von dem was Andreas schon schrieb, müsste das ganze auch so zu lösen sein.

SELECT CASE 'Kanten SOLL' WHEN 'Kanten IST' THEN COUNT(*) END / COUNT(*)  
FROM tabelle
WHERE 'Kanten SOLL' BETWEEN '29.07.2013' AND '02.08.2013'  

G Jörg
Biber
Biber 13.08.2013 um 12:07:18 Uhr
Goto Top
Moin,

Ergänzend zu den Vor-Postern:

drittens müssten die Spalten-Aliasnamen "as eins" und "as zwei" jeweils hinter der schliessenden Klammer des Inline-SELECTs stehen.

Ist das wirklich schon ein SQL-Server oder doch irgendeine Access 2.0-Anwendung, die ihr da zusammentrümmert?

Grüße
Biber
EricAG3
EricAG3 13.08.2013 um 12:27:13 Uhr
Goto Top
@andreas:
Die selects funktionieren einzeln und liefern ganze Zahlen zurück.
@lianen:
Fehlertext mit Deinem Select:
Meldung 8120, Ebene 16, Status 1, Zeile 2
Die 'tabelle.Kanten SOLL'-Spalte ist in der Auswahlliste ungültig, da sie nicht in einer Aggregatfunktion und nicht in der GROUP BY-Klausel enthalten ist.

ps.: Ich bin nicht der DB Admin.
MadMax
MadMax 13.08.2013 um 13:00:12 Uhr
Goto Top
Moinmoin,

also erstmal das select von EricAG3: da fehlt hinter den beiden Unterabfragen einfach nur ein Alias:
select eins / zwei
from
(select count(*) as eins from tabelle where [Kanten SOLL] = [Kanten IST] and [Kanten SOLL] between '29.07.2013' and '02.08.2013') AS A,  
(select count(*) as zwei from tabelle where [Kanten SOLL] between '29.07.2013' and '02.08.2013') AS B;  

Die implizite Umwandlung des Datums funktioniert zwar normalerweise, aber besser wäre es natürlich, es explizit per cast oder convert ins Datumsformat zu bringen.

Der Ansatz von LianenSchwinger würde mit einer kleinen Änderung auch funktionieren:
SELECT SUM (CASE [Kanten SOLL] WHEN [Kanten IST] THEN 1 ELSE 0 END) / COUNT(*)
FROM tabelle
WHERE [Kanten SOLL] BETWEEN '29.07.2013' AND '02.08.2013'  

Im Übrigen sollte man bei Divisionen auch immer prüfen, ob der Nenner 0 ist.

Gruß, Mad Max
Biber
Biber 13.08.2013 aktualisiert um 13:02:06 Uhr
Goto Top
Probier mal so:


select sum(eins) /count(*) as whatever from (
SELECT CASE 'Kanten SOLL'  
    WHEN 'Kanten IST' THEN 1   
    ELSE 0 
  END as eins
FROM tabelle
WHERE 'Kanten SOLL' BETWEEN '29.07.2013' AND '02.08.2013'  
)
;

Gruß
Biber
LianenSchwinger
LianenSchwinger 13.08.2013 aktualisiert um 13:09:35 Uhr
Goto Top
... ups, sorry mein Fehler

SELECT SUM(CASE 'Kanten SOLL' WHEN 'Kanten IST' THEN 1 END) / COUNT(*)   
FROM tabelle 
WHERE 'Kanten SOLL' BETWEEN '29.07.2013' AND '02.08.2013';  

G Jörg

OK MadMax war schneller face-smile
EricAG3
EricAG3 13.08.2013 um 13:27:34 Uhr
Goto Top
Vielleicht mal als Hintergrundinfo.
Der select dient zur Berechnung der Liefertreue. Pünktlich geliefert bedeutet Soll Datum = Ist Datum.
Die Summe aller pünktlichen Aufträge soll durch die Gesamtanzahl der Aufträge dividiert werden um eine prozentuale Liefertreue zu erhalten.

Führe ich die selects einzeln aus erhalte ich:

Select 1 (Anzahl pünktlich geliefertet Aufträge) Rückgabewert = 15
select count(*) as eins from tabelle where "Kanten SOLL" = "Kanten IST" and "Kanten SOLL" between '29.07.2013' and '02.08.2013';

Select 2 (Gesamtanzahl der Aufträge) Rückgabewert = 52
select count(*) as zwei from tabelle where "Kanten SOLL" between '29.07.2013' and '02.08.2013';

Ergibt eine Liefertreue von 29% (15/52*100).

Eure Vorschläge habe ich ausprobiert und sie funktionieren, rein technisch. Das Ergebnis ist falsch, er gibt die Zahl 0 aus.
MadMax
MadMax 13.08.2013 um 14:02:41 Uhr
Goto Top
Du hast nur die Lösungen von Biber und LianenSchwinger ausprobiert, die geben natürlich 0 aus. Wenn [Kanten SOLL] und [Kanten IST] statt mit eckigen Klammern oder doppelten Anführungszeichen mit einfachen Anführungszeichen umschlossen werden, sind es keine Spaltennamen, sondern Zeichenfolgen. Folglich ergibt
CASE 'Kanten SOLL' WHEN 'Kanten IST' THEN 1 ELSE 0 END  
immer 0 bzw. ohne ELSE NULL, weil die Zeichenfolgen eben nicht gleich sind.

Gruß, Mad Max
AndreasHoster
AndreasHoster 13.08.2013 um 14:45:23 Uhr
Goto Top
Unsere Vorschläge haben sich genau auf das bezogen, was du gepostet hast, in Deinem Posting stehen die Spaltennamen mit einem einfachen Anführungszeichen, Deine jetzt oben geposteten mit doppelten Anführungszeichen.
Das macht einen Unterschied, wie Mad Max schon festgestellt hat. Und wir gehen hier davon aus, das man die Statements per Copy & Paste ins Posting packt und damit in Deinem Original auch einfache Anführungszeichen drin sind.
Aber der Vorschlag von Mad Max sollte doch eigentlich tun, was kommt bei dem denn?
EricAG3
EricAG3 13.08.2013 um 15:02:50 Uhr
Goto Top
Mit "" (doppelte Anführungszeichen gibt es den Rückgabewert 0.

Mit ' (einfach A.) gibt es den Rückgabewert NULL.


Von MadMax:

SELECT SUM (CASE [Kanten SOLL] WHEN [Kanten IST] THEN 1 ELSE 0 END) / COUNT(*)

FROM tabelle

WHERE [Kanten SOLL] BETWEEN '29.07.2013' AND '02.08.2013';

--> Rückgabewert 0.
MadMax
MadMax 13.08.2013 um 15:57:17 Uhr
Goto Top
Tja, peinlich, das lerne ich in diesem Leben wahrscheinlich nicht mehr: zwei int-Werte dividiert ergibt wieder int. Also muß Zähler oder Nenner in float oder dec o.ä. konvertiert werden:
SELECT SUM (CASE [Kanten SOLL] WHEN [Kanten IST] THEN 1 ELSE 0 END) / convert (float, COUNT(*))
FROM tabelle
WHERE [Kanten SOLL] BETWEEN '29.07.2013' AND '02.08.2013'  

Wenns jetzt nicht paßt geb ich auf.

Gruß, Mad Max
EricAG3
EricAG3 13.08.2013 um 16:16:38 Uhr
Goto Top
super, ergebnis passt jetzt, danke! face-smile
EricAG3
EricAG3 13.08.2013 um 16:22:18 Uhr
Goto Top
kurze frage noch:
kann man den select noch irgendwie einfacher gestalten? gerade dieses konvertieren in float verstehe ich nicht, wieso war das nötig?
und geht es nicht indem man die zwei von mir erstellen selects irgendwie hintereinander abfragt? dann wären wir näher an meiner lösung...
Biber
Biber 13.08.2013 aktualisiert um 18:52:09 Uhr
Goto Top
Moin EricAG3,

Zitat von @EricAG3:
kurze frage noch:
kann man den select noch irgendwie einfacher gestalten?
Das Statement IST einfacher als dein Ansatz - schau nochmal hin.

gerade dieses konvertieren in float verstehe ich nicht, wieso war das nötig?
Das wurde gerade erklärt - eine Ganzzahl ( Beispiel: 15) geteilt durch eine andere Ganzzahl (Beispiel 52) ergibt wieder eine Ganzzahl.
Also nicht einen Wert "0,28763", sondern nur den ganzzahligen Teil--> 0.


und geht es nicht indem man die zwei von mir erstellen selects irgendwie hintereinander abfragt?
dann wären wir näher an meiner lösung...
Und weiter? Was ist erstrebenswert daran, für das Anzeigen EINES Wertes ZWEIMAL einen Count(*) mit derselben WHERE-Clause auf dieselbe Tabelle zu machen?
Hast du in irgendwelche QuadCore-Aktien investiert oder meinst du, wir sollten rumprassen, solange wir jung sind?

Abgesehen davon - die Länge oder Kürze eines Select-Statements sagt wenig aus über Effizienz, Performanz und Wartbarkeit.
Dennoch ist das erste Statement/dein Lösungsansatz doch wohl tippfehlerträchtiger (alle Feld-/Tabellennamen+Parameter müssen an zwei Stellen angepasst werden) und wirklich bei einer Tabelle mit mehr als 50 Sätzen bestimmt auch nicht performanter.

Auch nicht bei 5 Sätzen.

Ach ja, und wenn du das CASTen auf float nicht magst: du brauchst ja nur in der Rechnung eine Nicht-Ganzzahl mit einbauen.

... Select ..(sum(eins) * 100.00 /count(*) ) as LieferTroieInProzent

Grüße
Biber