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
- 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
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 667470
Url: https://administrator.de/forum/sql-mit-unterabfrage-in-gleicher-tabelle-667470.html
Ausgedruckt am: 29.04.2025 um 07:04 Uhr
13 Kommentare
Neuester Kommentar
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:
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.
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.
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
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
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.
Deine Eingangs erwähnte Spalte Status findet sich allerdings noch nicht in deinem Ausgangsselect wieder. Das * sollte dann auch durch explizite Spaltennamen ersetzt werden.
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
Wie wäre es mit einer View anstelle einer UDF? https://www.w3schools.com/SQL/sql_view.asp
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.