Benutzer mit den meisten Antworten
While Schleife Verständnisfrage

Frage
-
Hallo an alle,
ich beschäftige mich gerade ein wenig mit Programmierung im TSQL Bereich und will diverse Möglichkeiten austesten.
Aktuell habe ich folgendes Skript:
declare @para_year_start int SET @para_year_start = 2016 declare @para_month_start int SET @para_month_start = 2 declare @para_year_stop int SET @para_year_stop = 2017 declare @para_month_stop int SET @para_month_stop = 8 WHILE @para_year_start <= @para_year_stop BEGIN while @para_month_start <= @para_month_stop BEGIN print STR(@para_year_start) +' '+STR(@para_month_start); SET @para_month_start = @para_month_start + 1; WHILE @para_month_start = @para_month_stop BEGIN SET @para_year_start = @para_year_start + 1; SET @para_month_start=1; print'treffer'; END END END
Nun ist mein Problem das ich den geänderten Wert durch
SET@para_year_start =@para_year_start +1;
SET@para_month_start=1;
aus der zweiten While-Schleife an die erste wieder übergeben muss. Aber wie war das gleich noch mal? Da gab es doch irgendwas mit return oder? Ohne dieses Vorgehen bekommt die erste While-Schleife nie die Änderung mit und läuft ewig.
Leider habe ich noch nichts gefunden beim stöbern im Netz. Oder bin ich auf dem Holzweg?
Antworten
-
Hallo Toot,
ein RETURN kehrt zur aufrufen Prozedur zurück, was in T-SQL auch ein Trigger, Funktion sein kann. Bei einer WHILE Schleife gäbe es nur BREAK (verlässt die Schleife) oder CONTINUE (kehrt an den Schleifenanfang zurück).
Bei Deinem Konstrukt vermute ich aber, Du möchtest von Februar 2016 bis August 2017 Jahr und Monate erzeugen. Dafür brauchte man jedoch das dritte WHILE (was wenn überhaupt eher ein IF sein müsste) nicht:
DECLARE @para_year_start int = 2016, @para_month_start int = 2, @para_year_stop int = 2017, @para_month_stop int = 8; WHILE (@para_year_start <= @para_year_stop) BEGIN -- wenn nicht im Ende Jahr bis Monat 12, sonst bis zum Stop Monat WHILE (@para_year_start < @para_year_stop AND @para_month_start <= 12) OR (@para_month_start <= @para_month_stop) BEGIN PRINT STR(@para_year_start) + ' ' + STR(@para_month_start); SET @para_month_start += 1; END; SET @para_year_start += 1; SET @para_month_start = 1; END;
Wie zu sehen, reicht eine (etwas komplexere) Bedingung beim zweiten WHILE aus, um das Ziel zu erreichen. Man kann jedoch noch weiter gehen und es mit einer WHILE Schleife "bewältigen":
WHILE (@para_year_start < @para_year_stop OR (@para_year_start = @para_year_stop AND @para_month_start <= @para_month_stop)) BEGIN PRINT STR(@para_year_start) + ' ' + STR(@para_month_start); IF (@para_month_start = 12) BEGIN SET @para_year_start += 1 SET @para_month_start = 1; END ELSE BEGIN SET @para_month_start += 1; END; END;
Nebenbei habe ich einige Verkürzungen vorgenommen, wie den Einsatz von "+=" sowie die direkte Zuweisung beim DECLARE, was alle neueren SQL Server Versionen (ab 2008) beherrschen.
Die weitere Übung, das Ganze in einer SQL Anweisung vorzunehmen, überlasse ich jetzt aber Dir ;)
Gruß Elmar
- Als Antwort vorgeschlagen Christoph MuthmannEditor Mittwoch, 4. Januar 2017 12:28
- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05
-
Hi,
yop, das hilft :)
DECLARE @para_year_start INT = 2016 DECLARE @para_month_start INT = 11 DECLARE @para_year_stop INT = 2020 DECLARE @para_month_stop INT = 8; WITH Monate AS ( SELECT 1 AS Monat UNION ALL SELECT Monat + 1 FROM Monate AS M WHERE M.Monat <= 11 ), Jahre AS ( SELECT @para_year_start AS Jahr UNION ALL SELECT Jahr + 1 FROM Jahre AS J WHERE J.Jahr <= @para_year_stop ) SELECT * FROM Jahre j CROSS JOIN Monate m WHERE j.Jahr * 100 + m.Monat BETWEEN @para_year_start * 100 + @para_month_start AND @para_year_stop * 100 + @para_month_stop ORDER BY j.Jahr, m.Monat
Probier's mal damit.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort vorgeschlagen Christoph MuthmannEditor Mittwoch, 4. Januar 2017 12:28
- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05
-
Hi,
als Funktion evtl. sinnvoller:
CREATE FUNCTION [dbo].[fct_Monate] ( @YearStart INT, @YearStop INT, @MonthStart INT, @MonthStop INT ) RETURNS TABLE AS RETURN ( WITH Monate AS ( SELECT 1 AS Monat UNION ALL SELECT Monat + 1 FROM Monate AS M WHERE M.Monat <= 11 ), Jahre AS ( SELECT @YearStart AS Jahr UNION ALL SELECT Jahr + 1 FROM Jahre AS J WHERE J.Jahr <= @YearStop ) SELECT * FROM Jahre j CROSS JOIN Monate m WHERE j.Jahr * 100 + m.Monat BETWEEN @YearStart * 100 + @MonthStart AND @YearStop * 100 + @MonthStop )
Der Aufruf sähe dann bspw. so aus:
SELECT * FROM dbo.[fct_Monate]( 2016, 2022, 8, 2 ) ORDER BY Jahr, Monat
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05
Alle Antworten
-
Hallo Toot,
ein RETURN kehrt zur aufrufen Prozedur zurück, was in T-SQL auch ein Trigger, Funktion sein kann. Bei einer WHILE Schleife gäbe es nur BREAK (verlässt die Schleife) oder CONTINUE (kehrt an den Schleifenanfang zurück).
Bei Deinem Konstrukt vermute ich aber, Du möchtest von Februar 2016 bis August 2017 Jahr und Monate erzeugen. Dafür brauchte man jedoch das dritte WHILE (was wenn überhaupt eher ein IF sein müsste) nicht:
DECLARE @para_year_start int = 2016, @para_month_start int = 2, @para_year_stop int = 2017, @para_month_stop int = 8; WHILE (@para_year_start <= @para_year_stop) BEGIN -- wenn nicht im Ende Jahr bis Monat 12, sonst bis zum Stop Monat WHILE (@para_year_start < @para_year_stop AND @para_month_start <= 12) OR (@para_month_start <= @para_month_stop) BEGIN PRINT STR(@para_year_start) + ' ' + STR(@para_month_start); SET @para_month_start += 1; END; SET @para_year_start += 1; SET @para_month_start = 1; END;
Wie zu sehen, reicht eine (etwas komplexere) Bedingung beim zweiten WHILE aus, um das Ziel zu erreichen. Man kann jedoch noch weiter gehen und es mit einer WHILE Schleife "bewältigen":
WHILE (@para_year_start < @para_year_stop OR (@para_year_start = @para_year_stop AND @para_month_start <= @para_month_stop)) BEGIN PRINT STR(@para_year_start) + ' ' + STR(@para_month_start); IF (@para_month_start = 12) BEGIN SET @para_year_start += 1 SET @para_month_start = 1; END ELSE BEGIN SET @para_month_start += 1; END; END;
Nebenbei habe ich einige Verkürzungen vorgenommen, wie den Einsatz von "+=" sowie die direkte Zuweisung beim DECLARE, was alle neueren SQL Server Versionen (ab 2008) beherrschen.
Die weitere Übung, das Ganze in einer SQL Anweisung vorzunehmen, überlasse ich jetzt aber Dir ;)
Gruß Elmar
- Als Antwort vorgeschlagen Christoph MuthmannEditor Mittwoch, 4. Januar 2017 12:28
- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05
-
Danke Elmar!
ja manchmal denkt man einfach viel zu kompliziert.
Schau dir doch mal bitte das an und sag mir mal was du davon hälst?
declare @para_year_start int SET @para_year_start = 2016 declare @para_month_start int SET @para_month_start = 11 declare @para_year_stop int SET @para_year_stop = 2020 declare @para_month_stop int SET @para_month_stop = 8 --print Cast(str(@para_year_start)+RIGHT('00' + CONVERT(NVARCHAR(2), @para_month_start), 2) as int); while Cast(str(@para_year_start)+RIGHT('00' + CONVERT(NVARCHAR(2), @para_month_start), 2) as int) <= Cast(str(@para_year_stop)+RIGHT('00' + CONVERT(NVARCHAR(2), @para_month_stop), 2) as int) BEGIN IF @para_month_start <12 BEGIN --PRINT Cast(str(@para_year_start)+RIGHT('00' + CONVERT(NVARCHAR(2), @para_month_start), 2) as int); PRINT '|'+str(@para_year_start)+'|'+ str(@para_month_start)+'|' SET @para_month_start=@para_month_start+1 Continue END ELSE BEGIN --PRINT Cast(str(@para_year_start)+RIGHT('00' + CONVERT(NVARCHAR(2), @para_month_start), 2) as int); PRINT '|'+str(@para_year_start)+'|'+ str(@para_month_start)+'|' SET @para_month_start = 01 SET @para_year_start = @para_year_start+1 END END
Ich habe es jetzt nicht weiter vereinfacht aber das würde ich danke deinen Tipps noch tuen. Aber wie bekomme ich jetzt das Ergebnis in einer "Tabellenform" angezeigt. Also Spalte Jahr und Spalte Monat und darunter die Werte?
Um das besser zu verdeutlichen habe ich die Print-Ausgaben angepasst damit man sieht was ich meine.
-
Hi,
ich glaube, Du gehst komplett verkehrt an die Sache ran. Was genau soll denn bitte bei deiner "Abfrage" rauskommen?
Wenn Du eine Datensatzliste als Ergebnis willst, solltest Du auch irgendwo etwas selektieren. Das tust Du aber nicht.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Stefan,
nein ich möchte nichts selektieren. Da ich das auch nicht benötige. Am ende meiner mühen soll eine Prozedur herauskommen. Wenn ich diese 4 Parameter übergebe und eben besagte Tabelle herauskommt. Ich benötige dies für diverse Reports.
-
Hi,
wenn eine Tabelle rauskommen soll, willst Du etwas selektieren. In welcher Form auch immer.
Was genau also soll bei der Prozedur herauskommen?
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo Stefan,
naja eine Tabelle soll rauskommen in der Form
| 2016| 11|
| 2016| 12|
| 2017| 1|
| 2017| 2|
| 2017| 3|
| 2017| 4|
| 2017| 5|
| 2017| 6|
| 2017| 7|
| 2017| 8|
| 2017| 9|
| 2017| 10|
| 2017| 11|
| 2017| 12|
| 2018| 1|
Hilft dir das weiter?
-
Hi,
yop, das hilft :)
DECLARE @para_year_start INT = 2016 DECLARE @para_month_start INT = 11 DECLARE @para_year_stop INT = 2020 DECLARE @para_month_stop INT = 8; WITH Monate AS ( SELECT 1 AS Monat UNION ALL SELECT Monat + 1 FROM Monate AS M WHERE M.Monat <= 11 ), Jahre AS ( SELECT @para_year_start AS Jahr UNION ALL SELECT Jahr + 1 FROM Jahre AS J WHERE J.Jahr <= @para_year_stop ) SELECT * FROM Jahre j CROSS JOIN Monate m WHERE j.Jahr * 100 + m.Monat BETWEEN @para_year_start * 100 + @para_month_start AND @para_year_stop * 100 + @para_month_stop ORDER BY j.Jahr, m.Monat
Probier's mal damit.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort vorgeschlagen Christoph MuthmannEditor Mittwoch, 4. Januar 2017 12:28
- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05
-
Hi,
als Funktion evtl. sinnvoller:
CREATE FUNCTION [dbo].[fct_Monate] ( @YearStart INT, @YearStop INT, @MonthStart INT, @MonthStop INT ) RETURNS TABLE AS RETURN ( WITH Monate AS ( SELECT 1 AS Monat UNION ALL SELECT Monat + 1 FROM Monate AS M WHERE M.Monat <= 11 ), Jahre AS ( SELECT @YearStart AS Jahr UNION ALL SELECT Jahr + 1 FROM Jahre AS J WHERE J.Jahr <= @YearStop ) SELECT * FROM Jahre j CROSS JOIN Monate m WHERE j.Jahr * 100 + m.Monat BETWEEN @YearStart * 100 + @MonthStart AND @YearStop * 100 + @MonthStop )
Der Aufruf sähe dann bspw. so aus:
SELECT * FROM dbo.[fct_Monate]( 2016, 2022, 8, 2 ) ORDER BY Jahr, Monat
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Stefan FalzModerator Mittwoch, 14. Februar 2018 12:05