gbn-ws2
Goto Top

SQL mit Unterabfrage in gleicher Tabelle

Folgender Fall liegt vor. Es gibt eine Tabelle mit den Spalten:
- Auftrag
- Kürzel
- Licht
- Farbe
- Status.

In die Tabelle kommen jetzt Werte, die Messungen betreffen. Teile werden vor Bearbeitung gemessen und danach. Beide Messungen kommen in eine Tabell. Das heißt, es gibt für das gleiche Teil (über Auftrag und Kürzel eindeutig identifizierbar) jeweils 2 Einträge in der Tabelle. Diese werden über den Status gekennzeichnet (1 für vorher und 2 für nachher).
Für die Begutachtung der Bearbeitung sollen die 2 über Auftrag und Kürzel zusammengehörenden Datensätze in einer neuen Tabelle dargestellt werden. Dazu versuche ich im SQL Server Management Studio eine User Definde Function zu erstellen, denen ich die Parameter für den Auftrag und das Kürzel übergebe und die dann eine Tabelle zurückgibt. Leider führt bei mir dem Umweg über die UDF, weil ich den Fall nicht mit einem SQL Statement hinbekommen habe. Die Unterabfragen auf den 2. dazugehörigen Datensatz kontte ich nicht zusammenbasteln, da die Übergabeparameter für die WHERE-Klausel sich nicht auf den Datensatz der Abfrage beziehen konnten.

Beispiel Tabelle jetzt:
1000; A; 11; 2;1 (für vor der Bearbeitung)
1000; A; 9; 3; 2 (nach der Bearbeitung)

Inhalt der der gewünschen Zieltabelle sollte sein:
1000; A; 11; 2; 9; 3
Vielleich noch eine Spalte am Ende für den Anteil vom Licht vor und nach der Bearbeitung (9 zu 11 = 81,8%)

Derzeit bin ich so weit, dass die UDF wie folgt aussieht:

CREATE FUNCTION [dbo].[fnLichtwerte_Klar_B0] (@BID Int, @sanr Int, @eanr Int)
RETURNS @tbllichtwerte TABLE
(Auftrag char(24),
Kuerzel char(1),
Datum_K smalldatetime,
P_K real,
L_K real,
x_K real,
y_K real,
Datum_B smalldatetime,
P_B real,
L_B real,
x_B real,
y_B real,
Absorption real)
AS
BEGIN
DECLARE @auftrag char(24)
DECLARE @datum_k datetime2, @datum_b datetime
DECLARE @p_k real, @l_k real, @x_k real, @y_k real
DECLARE @p_b real, @l_b real, @x_b real, @y_b real
DECLARE @KB int, @kuerzel char(1), @b_id int, @verw int
DECLARE @absorption real


DECLARE Messwerte_Klar CURSOR LOCAL STATIC

-- Schleife durch die Klarmessungen
FOR
SELECT Auftrag.Produktion_Vorgangsnummer,
Messwerte.Produktion_Kuerzel,
Messung.Produktion_Datum,
Messwerte.Produktion_Leistung,
Messwerte.Produktion_Korr_Lichtstrom,
Messwerte.Produktion_Korr_Farbort_X,
Messwerte.Produktion_Korr_Farbort_Y,
'1900-01-01', 0, 0, 0, 0, 0
FROM dbo.tblProduktion_BrennerMessung AS Messwerte
INNER JOIN dbo.tblProduktion_Messung AS Messung ON Messwerte.Produktion_Verweis_Messung_ID = Messung.Produktion_Messung_ID
INNER JOIN dbo.tblProduktion_Messauftrag AS Auftrag ON Messung.Produktion_Verweis_Messauftrag_ID = Auftrag.Produktion_Messauftrag_ID
WHERE (Auftrag.Produktion_Verweis_Brennertyp_ID = @bid) AND Messwerte.Produktion_MessungVerworfen = 0 AND Messung.Produktion_Messungstyp_Klar_Beschichtet = 1 AND (Auftrag.Produktion_Vorgangsnummer BETWEEN @sanr AND @eanr);

OPEN Messwerte_Klar

FETCH NEXT FROM Messwerte_Klar INTO @auftrag, @kuerzel, @datum_k, @p_k, @l_k, @x_k, @y_k, @datum_b, @p_b, @l_b, @x_b, @y_b, @absorption

WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN
INSERT INTO @tbllichtwerte
VALUES (@Auftrag, @kuerzel, @datum_k, @p_k, @l_k, @x_k, @y_k, @datum_b, @p_b, @l_b, @x_b, @y_b, @absorption);
END
FETCH NEXT FROM Messwerte_Klar INTO @auftrag, @kuerzel, @datum_k, @p_k, @l_k, @x_k, @y_k, @datum_b, @p_b, @l_b, @x_b, @y_b, @absorption
END

CLOSE Messwerte_Klar
DEALLOCATE Messwerte_Klar
RETURN
END

Leider kenne ich den Weg nicht, wie ich die Nullen für den Nachbearbeitungszustand durch Unterabfragen ersetzen kann.
DIE UDF wäre nur meine 2t-liebste Lösung. Am besten wäre es mit einem SQL-Statement.

Bin gespannt, ob mir jemand helfen kann.

Danke

Content-Key: 667470

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

Printed on: April 25, 2024 at 07:04 o'clock

Member: GBN-WS2
GBN-WS2 Jun 10, 2021 at 08:56:54 (UTC)
Goto Top
Es muss "SQL mit Unterabfrage" heißen
Member: ukulele-7
ukulele-7 Jun 10, 2021 updated at 09:02:34 (UTC)
Goto Top
Klingt für mich nach viel zu kompliziert gedacht. Ist doch einfach ein Join in einem Select (den man dann auch als View verfügbar machen kann), in etwa so:
SELECT * FROM tabelle t1 LEFT JOIN tabelle t2 ON t1.Auftrag = t2.Auftrag AND t1.Kürzel = t2.Kürzel AND t2.Status = 2 WHERE t1.Status = 1

PS: Ich gehe davon aus das sichergestellt ist, das Auftrag + Kürzel immer eindeutig ist und es immer mind. 1x Status = 1 gibt und 0 bis 1 mal Status 2.
Member: GBN-WS2
GBN-WS2 Jun 10, 2021 at 09:08:19 (UTC)
Goto Top
Interessanter Ansatz. Leider sind mit nur die Inner Joins so richtig bekannt. Ich probieren das mal mit dem Left Join. Danke vorerst.
Member: GBN-WS2
GBN-WS2 Jun 10, 2021 at 09:20:04 (UTC)
Goto Top
Hab etwas genauer hingesehen. Die Daten über den Status sowie andere Informationen kommen aus insgesamt 3 Tabellen, die jetzt schon innergejoint sind:
SELECT Auftrag.Produktion_Vorgangsnummer,
Messwerte.Produktion_Kuerzel,
Messung.Produktion_Datum,
Messwerte.Produktion_Leistung,
Messwerte.Produktion_Korr_Lichtstrom,
Messwerte.Produktion_Korr_Farbort_X,
Messwerte.Produktion_Korr_Farbort_Y,
'1900-01-01', 0, 0, 0, 0, 0
FROM dbo.tblProduktion_BrennerMessung AS Messwerte
INNER JOIN dbo.tblProduktion_Messung AS Messung ON Messwerte.Produktion_Verweis_Messung_ID = Messung.Produktion_Messung_ID
INNER JOIN dbo.tblProduktion_Messauftrag AS Auftrag ON Messung.Produktion_Verweis_Messauftrag_ID = Auftrag.Produktion_Messauftrag_ID
WHERE (Auftrag.Produktion_Verweis_Brennertyp_ID = @bid) AND Messwerte.Produktion_MessungVerworfen = 0 AND Messung.Produktion_Messungstyp_Klar_Beschichtet = 1 AND (Auftrag.Produktion_Vorgangsnummer BETWEEN @sanr AND @eanr);

Wie kann ich hier zusätzlich den LEFT JOIN mitverwenden?
Member: em-pie
em-pie Jun 10, 2021 updated at 10:00:59 (UTC)
Goto Top
Moin,

eine Bitte: verwende unbedingt die code-Tags (Ohne die Leerzeichen): < code > MEIN CODE < /code >
Die kannst du auch nachträglich noch in deine Posts einbinden.

Ein LEFT JOIN (oder auch Right oder Outer Join) nutzt man exakt wie ein INNER JOIN, nur das Ergebnis ist jedes mal "anders".

Hier ist das ganz gut erklärt, insbesondere auch durch die Grafik:
https://stackoverflow.com/questions/406294/left-join-vs-left-outer-join- ...

Gruß
em-pie
Member: ukulele-7
Solution ukulele-7 Jun 10, 2021 updated at 12:03:18 (UTC)
Goto Top
LEFT JOIN ist genauso wie der INNER JOIN absolute Basisfunktionalität. Dabei enthält das Ergebnis auch Datensätze der ersten Tabelle (die im FROM-Teil) zu denen keine passenden Datensätze in der 2ten Tabelle gefunden wurden. Das dürfte in deinem Fall vor kommen wenn Messung 1 statt gefunden hat aber Messung 2 noch aus steht.

Was die "Ursprungstabelle" angeht: Man macht es sich gern einfach und in deinem Szenario wäre das wohl auch übersichtlicher. Daher fasse ich dein Query gar nicht an sondern packe das entweder in eine vorgelagerte View oder in eine WITH-clause. Der Vorteil ist dabei ganz klar das man gar nicht das Query verstehen muss um es mit sich selbst zu joinen sondern als eine Ausgangstabelle behandelt. Nachteil ist wohl das es anders theoretisch performanter sein kann.
WITH tabelle AS (
SELECT Auftrag.Produktion_Vorgangsnummer,
Messwerte.Produktion_Kuerzel,
Messung.Produktion_Datum,
Messwerte.Produktion_Leistung,
Messwerte.Produktion_Korr_Lichtstrom,
Messwerte.Produktion_Korr_Farbort_X,
Messwerte.Produktion_Korr_Farbort_Y,
'1900-01-01', 0, 0, 0, 0, 0  
FROM dbo.tblProduktion_BrennerMessung AS Messwerte
INNER JOIN dbo.tblProduktion_Messung AS Messung ON Messwerte.Produktion_Verweis_Messung_ID = Messung.Produktion_Messung_ID
INNER JOIN dbo.tblProduktion_Messauftrag AS Auftrag ON Messung.Produktion_Verweis_Messauftrag_ID = Auftrag.Produktion_Messauftrag_ID
WHERE (Auftrag.Produktion_Verweis_Brennertyp_ID = @BID) AND Messwerte.Produktion_MessungVerworfen = 0 AND Messung.Produktion_Messungstyp_Klar_Beschichtet = 1 AND (Auftrag.Produktion_Vorgangsnummer BETWEEN @SANr AND @EANr)
)
SELECT *
FROM tabelle t1
LEFT JOIN tabelle t2
ON t1.Produktion_Vorgangsnummer = t2.Produktion_Vorgangsnummer 
AND t1.Produktion_Kuerzel = t2.Produktion_Kuerzel
AND t2.Status = 2
WHERE t1.Status = 1
Deine Eingangs erwähnte Spalte Status findet sich allerdings noch nicht in deinem Ausgangsselect wieder. Das * sollte dann auch durch explizite Spaltennamen ersetzt werden.
Member: GBN-WS2
GBN-WS2 Jun 11, 2021 at 09:35:33 (UTC)
Goto Top
Danke bis hier her. Ich hab das Status-Feld noch eingebaut und etwas aufgeräumt. Die Abfrage geht ohne Fehlermeldung und liefert Daten. Jetzt muss ich nur noch sehen, dass ich das Ganze in eine UDF auf dem SQL-SERVER hinterlegt bekomme, die eine Tabelle ausgibt und der ich die Parameter BID, SANr und SENr übergeben kann.
Member: ukulele-7
ukulele-7 Jun 11, 2021 at 09:53:40 (UTC)
Goto Top
Wie wäre es mit einer View anstelle einer UDF? https://www.w3schools.com/SQL/sql_view.asp
Member: GBN-WS2
GBN-WS2 Jun 11, 2021 at 10:22:35 (UTC)
Goto Top
Ich denke, an eine View kann man keine Parameter übergeben. Ich muss aber die BID, SANr und SENr dynamisch aus einem Frontend-Formular auslesen und übergeben.
Member: ukulele-7
Solution ukulele-7 Jun 11, 2021 at 10:58:14 (UTC)
Goto Top
Die View fragst du mit einem Select ab, der Select beinhaltet im WHERE-Teil die Parameter...
Member: GrueneSosseMitSpeck
GrueneSosseMitSpeck Jun 11, 2021 at 16:42:54 (UTC)
Goto Top
auch wenns nach schwarzer Magie klingt - schreib das als verschachtelte Select Statements hin, alle gängigen SQL Server optimieren das später so daß ein Join im Abfrageplan auftaucht. Weil ansosnten die clientseitig definierten Joins per SQL tlw die serverseitige Optimierung (speziell beim MS SQL Server) manchmal in die Irre treibt und der dann extrem lange für triviale Abfragen braucht.
Member: GBN-WS2
GBN-WS2 Jun 14, 2021 updated at 13:38:32 (UTC)
Goto Top
Ich möchte meine Endlösung hier posten, falls es noch jemand anders nutzen sollte:

Es gibt eine View qurLichtwerte_mit_Absorption (folgt am Ende). Diese wird wie folgt aufgerufen:
"SELECT * FROM qurLichtwerte_mit_Absorption WHERE (Produktion_Verweis_Brennertyp_ID = " & BID & " AND ((Produktion_Vorgangsnummer >= '" & SANr & "') AND (Produktion_Vorgangsnummer <= '" & SENr & "')));"  
Die View (qurLichtwerte_mit_Absorption) besteht aus:
WITH tabelle AS (SELECT Auftrag.Produktion_Vorgangsnummer, Messwerte.Produktion_Kuerzel, Auftrag.Produktion_Verweis_Brennertyp_ID, Messung.Produktion_Datum, Messwerte.Produktion_Leistung, Messwerte.Produktion_Korr_Lichtstrom, Messwerte.Produktion_Korr_Farbort_X, Messwerte.Produktion_Korr_Farbort_Y, Messung.Produktion_Messungstyp_Klar_Beschichtet 
          FROM dbo.tblProduktion_BrennerMessung AS Messwerte 
          INNER JOIN dbo.tblProduktion_Messung AS Messung ON Messwerte.Produktion_Verweis_Messung_ID = Messung.Produktion_Messung_ID 
          INNER JOIN dbo.tblProduktion_Messauftrag AS Auftrag ON Messung.Produktion_Verweis_Messauftrag_ID = Auftrag.Produktion_Messauftrag_ID
          WHERE (Messwerte.Produktion_MessungVerworfen = 0))
SELECT        t1.Produktion_Vorgangsnummer, t1.Produktion_Kuerzel, t1.Produktion_Verweis_Brennertyp_ID, t1.Produktion_Datum AS Date_Klar, t1.Produktion_Leistung AS P_Klar, t1.Produktion_Korr_Lichtstrom AS L_Klar, t1.Produktion_Korr_Farbort_X AS x_Klar, t1.Produktion_Korr_Farbort_Y AS y_Klar, t2.Produktion_Datum AS Date_Besch, t2.Produktion_Leistung AS P_Besch, 2.Produktion_Korr_Lichtstrom AS L_Besch, t2.Produktion_Korr_Farbort_X AS x_Besch, t2.Produktion_Korr_Farbort_Y AS y_Besch, t2.Produktion_Leistung / t1.Produktion_Leistung - 1 AS P_Dif, (t2.Produktion_Korr_Lichtstrom / t1.Produktion_Korr_Lichtstrom - 1) * - 100 AS Absorption
 FROM  tabelle AS t1 
 LEFT OUTER JOIN tabelle AS t2 ON t1.Produktion_Vorgangsnummer = t2.Produktion_Vorgangsnummer AND t1.Produktion_Kuerzel = t2.Produktion_Kuerzel AND t2.Produktion_Messungstyp_Klar_Beschichtet = 2
 WHERE (t1.Produktion_Messungstyp_Klar_Beschichtet = 1)
Member: em-pie
em-pie Jun 14, 2021 at 13:22:37 (UTC)
Goto Top
Nutze, wie oben schon geschrieben, doch bitte die Code-Tags.
Das kann hier doch keiner ordentlich lesen!