Benutzer mit den meisten Antworten
Aufteilen des Umsatzes auf einzelne Monate des Projektzeitraumes

Frage
-
Hallo an alle
Ich muss ein interessantes Problem lösen, aber mir fällt keine Vorgehensweise ein. Vielleicht könnt ihr mir helfen.
Eine Kundendatenbank verwaltet Projekte, die unter anderem einen Umsatz und einen Zeitraum beinhalten. Z.B. Projekt A geht vom 16.04.2019 bis zum 31.08.2019 und bringt einen Umsatz von 1000 Euro. Die Projektzeiten können nur wenige Tage dauern oder auch jahrübergreifend (10.12.2018 bis 31.01.2020).
Meine Aufgabe besteht jetzt darin, dass ich den Projektumsatz auf die einzelnen Monate des Projekts umrechnen muss. Um beim obigen Beispiel zu bleiben:
So soll das ganze dann aussehen.
16.04.2019 - 31.08.2019 = 1000 Euro
16.04.2019 - 30.04.2019 = 111,08 Euro
01.05.2019 - 31.05.2019 = 222,23 Euro
01.06.2019 - 30.06.2019 = 222,23 Euro
01.07.2019 - 31.07.2019 = 222,23 Euro
01.08.2019 - 31.08.2019 = 222,23 Euro
Nur habe ich keinen Plan, wie ich das in einer View bzw. Storedproc umsetzen soll. Kann mir einer von euch einen Tipp geben?
Thorsten Schröer Dipl-Inform (FH) - EDV, Beratung & Service - double-D-IT -Office- / Information system support Bismarckstraße 18a Germany-12169 Berlin Steglitz phone: +49-(0)30-303286770 fax: +49-(0)30-303286779
Antworten
-
Hallo Thorsten,
hier ein Beispiel für eine tageweise Umrechnung der Ausgaben auf Monate.
Schönen Abend.
IF OBJECT_ID(N'tempdb..#Calendar') IS NOT NULL DROP TABLE #Calendar; DECLARE @DateMax DATETIME, @DateMin DATETIME; DECLARE @Periode VARCHAR(MAX); DECLARE @Zeitachse CHAR(1); SET @DateMin = '01.01.2019'; SET @DateMax = '31.12.2020'; SET @Zeitachse = 'm'; /* Schalter: Y = Jahr; Q = Quartal; M = Monat */ DECLARE @Projekte TABLE ( BeginnProjekt DATETIME, EndeProjekt DATETIME, Ausgaben MONEY ); INSERT INTO @Projekte VALUES ( '16.04.2019', '31.08.2019', 1000 ); CREATE TABLE #Calendar( Jahr int NULL, Quartal int NULL, Monat CHAR (2) NULL, Beginn_Periode DATETIME, Ende_Periode DATETIME, Periode varchar(10) NULL, Periodentage INT); WITH Calendar_func AS ( SELECT @DateMin AS DateDay UNION ALL SELECT DATEADD(DAY, 1, DateDay) FROM Calendar_func WHERE DateDay < @DateMax ) INSERT INTO #Calendar (Jahr, Quartal, Monat, Beginn_Periode, Ende_Periode, Periode, Periodentage) SELECT DISTINCT DATEPART(yy, DateDay) AS [Jahr], CASE WHEN @Zeitachse = 'Y' THEN NULL ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEPART(qq, DateDay) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEPART(qq, DateDay) ELSE NULL END END END AS [Quartal], CASE WHEN @Zeitachse = 'Y' THEN NULL ELSE CASE WHEN @Zeitachse = 'Q' THEN NULL ELSE DATEPART(mm, DateDay) END END AS [Monat], CASE WHEN @Zeitachse = 'Y' THEN DATEADD(yy,DATEDIFF(yy,0,DateDay),0) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEADD(qq,DATEDIFF(qq,0,DateDay),0) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEADD(mm,DATEDIFF(mm,0,DateDay),0) ELSE NULL END END END AS [Beginn_Periode], CASE WHEN @Zeitachse = 'Y' THEN DATEADD(yy,DATEDIFF(yy,0,DateDay)+1,-1) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEADD(qq,DATEDIFF(qq,0,DateDay)+1,-1) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEADD(mm,DATEDIFF(mm,0,DateDay)+1,-1) ELSE NULL END END END AS [Ende_Periode], CASE WHEN @Zeitachse = 'Y' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) ELSE CASE WHEN @Zeitachse = 'Q' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) + ' - Q' + CAST (DATEPART(qq, DateDay) AS CHAR (1)) ELSE CASE WHEN @Zeitachse = 'M' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) + ' - ' + CASE WHEN DATEPART(mm, DateDay) < 10 THEN RIGHT('0' + CONVERT( varchar, DATEPART(mm, DateDay) ), 2) ELSE CONVERT(VARCHAR, DATEPART(mm, DateDay)) END ELSE NULL END END END AS [Periode], CASE WHEN @Zeitachse = 'Y' THEN DATEDIFF (d, DATEADD(yy,DATEDIFF(yy,0,DateDay),0), DATEADD(yy,DATEDIFF(yy,0,DateDay)+1,-0)) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEDIFF (d, DATEADD(qq,DATEDIFF(qq,0,DateDay),0), DATEADD(qq,DATEDIFF(qq,0,DateDay)+1,-0)) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEDIFF (d, DATEADD(mm,DATEDIFF(mm,0,DateDay),0), DATEADD(mm,DATEDIFF(mm,0,DateDay)+1,-0)) END END END AS [Periodentage] FROM Calendar_func OPTION ( MAXRECURSION 0 ) SELECT * FROM @Projekte SELECT Periode, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END as von, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END AS bis, DATEDIFF (dd, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END) + 1 AS Tage, Ausgaben * (DATEDIFF (dd, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END) + 1) / (DATEDIFF (dd, BeginnProjekt, EndeProjekt) + 1) AS Ausgaben_Periode, DATEDIFF (dd, BeginnProjekt, EndeProjekt) + 1 AS Projektdauer, Ausgaben FROM #Calendar c RIGHT OUTER JOIN @Projekte p ON (c.Ende_Periode >= p.BeginnProjekt AND c.Beginn_Periode <=p.EndeProjekt)
- Bearbeitet Joerg_x Freitag, 13. Dezember 2019 20:58
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 20. Dezember 2019 13:14
- Als Antwort markiert Thorsten Schröer Freitag, 20. Dezember 2019 13:20
-
Hallo Thorsten,
vermutlich hast Du andere Spracheinstellungen.
Ergänze bitte den Code als erste Zeile:
SET dateformat dmy;
Schönen Tag.
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 20. Dezember 2019 13:14
- Als Antwort markiert Thorsten Schröer Freitag, 20. Dezember 2019 13:20
Alle Antworten
-
Hallo Thorsten,
gibt es immer nur Start, Ende und Umsatz? Soll also die Berechnung immer mit einem zusammenhängendem Zeitraum erfolgen?
Falls nicht, poste bitte mal deine Tabellenstruktur und Beispieldaten, die exakt zu deinem gewünschten Ergebnis passen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport -
Die einfachste Variante ist, die Anzahl Tage jeder Periode zu berechnen:
https://docs.microsoft.com/de-de/sql/t-sql/functions/datediff-transact-sql?view=sql-server-ver15
Dann kannst du den Tageswert ausrechnen und mit den jeweiligen Tagen je Monat wieder ausmultiplizieren.Sind allerdings Lücken in den Einzelperioden, so ist die Summe vorher zu berechnen:
sum(datediff(day, FromDate, ToDate)) over()
Möchtest du halbe/Ganze Monate geht das am Besten über Wochen:
ceil((Datediff(...) / 7)
Möglichkeiten gibt es da mehrere.
-
Hallo Thorsten,
hier ein Beispiel für eine tageweise Umrechnung der Ausgaben auf Monate.
Schönen Abend.
IF OBJECT_ID(N'tempdb..#Calendar') IS NOT NULL DROP TABLE #Calendar; DECLARE @DateMax DATETIME, @DateMin DATETIME; DECLARE @Periode VARCHAR(MAX); DECLARE @Zeitachse CHAR(1); SET @DateMin = '01.01.2019'; SET @DateMax = '31.12.2020'; SET @Zeitachse = 'm'; /* Schalter: Y = Jahr; Q = Quartal; M = Monat */ DECLARE @Projekte TABLE ( BeginnProjekt DATETIME, EndeProjekt DATETIME, Ausgaben MONEY ); INSERT INTO @Projekte VALUES ( '16.04.2019', '31.08.2019', 1000 ); CREATE TABLE #Calendar( Jahr int NULL, Quartal int NULL, Monat CHAR (2) NULL, Beginn_Periode DATETIME, Ende_Periode DATETIME, Periode varchar(10) NULL, Periodentage INT); WITH Calendar_func AS ( SELECT @DateMin AS DateDay UNION ALL SELECT DATEADD(DAY, 1, DateDay) FROM Calendar_func WHERE DateDay < @DateMax ) INSERT INTO #Calendar (Jahr, Quartal, Monat, Beginn_Periode, Ende_Periode, Periode, Periodentage) SELECT DISTINCT DATEPART(yy, DateDay) AS [Jahr], CASE WHEN @Zeitachse = 'Y' THEN NULL ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEPART(qq, DateDay) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEPART(qq, DateDay) ELSE NULL END END END AS [Quartal], CASE WHEN @Zeitachse = 'Y' THEN NULL ELSE CASE WHEN @Zeitachse = 'Q' THEN NULL ELSE DATEPART(mm, DateDay) END END AS [Monat], CASE WHEN @Zeitachse = 'Y' THEN DATEADD(yy,DATEDIFF(yy,0,DateDay),0) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEADD(qq,DATEDIFF(qq,0,DateDay),0) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEADD(mm,DATEDIFF(mm,0,DateDay),0) ELSE NULL END END END AS [Beginn_Periode], CASE WHEN @Zeitachse = 'Y' THEN DATEADD(yy,DATEDIFF(yy,0,DateDay)+1,-1) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEADD(qq,DATEDIFF(qq,0,DateDay)+1,-1) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEADD(mm,DATEDIFF(mm,0,DateDay)+1,-1) ELSE NULL END END END AS [Ende_Periode], CASE WHEN @Zeitachse = 'Y' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) ELSE CASE WHEN @Zeitachse = 'Q' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) + ' - Q' + CAST (DATEPART(qq, DateDay) AS CHAR (1)) ELSE CASE WHEN @Zeitachse = 'M' THEN CAST (DATEPART(yy, DateDay) AS CHAR (4)) + ' - ' + CASE WHEN DATEPART(mm, DateDay) < 10 THEN RIGHT('0' + CONVERT( varchar, DATEPART(mm, DateDay) ), 2) ELSE CONVERT(VARCHAR, DATEPART(mm, DateDay)) END ELSE NULL END END END AS [Periode], CASE WHEN @Zeitachse = 'Y' THEN DATEDIFF (d, DATEADD(yy,DATEDIFF(yy,0,DateDay),0), DATEADD(yy,DATEDIFF(yy,0,DateDay)+1,-0)) ELSE CASE WHEN @Zeitachse = 'Q' THEN DATEDIFF (d, DATEADD(qq,DATEDIFF(qq,0,DateDay),0), DATEADD(qq,DATEDIFF(qq,0,DateDay)+1,-0)) ELSE CASE WHEN @Zeitachse = 'M' THEN DATEDIFF (d, DATEADD(mm,DATEDIFF(mm,0,DateDay),0), DATEADD(mm,DATEDIFF(mm,0,DateDay)+1,-0)) END END END AS [Periodentage] FROM Calendar_func OPTION ( MAXRECURSION 0 ) SELECT * FROM @Projekte SELECT Periode, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END as von, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END AS bis, DATEDIFF (dd, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END) + 1 AS Tage, Ausgaben * (DATEDIFF (dd, CASE WHEN BeginnProjekt > c.Beginn_Periode THEN BeginnProjekt ELSE c.Beginn_Periode END, CASE WHEN EndeProjekt < c.Ende_Periode THEN EndeProjekt ELSE c.Ende_Periode END) + 1) / (DATEDIFF (dd, BeginnProjekt, EndeProjekt) + 1) AS Ausgaben_Periode, DATEDIFF (dd, BeginnProjekt, EndeProjekt) + 1 AS Projektdauer, Ausgaben FROM #Calendar c RIGHT OUTER JOIN @Projekte p ON (c.Ende_Periode >= p.BeginnProjekt AND c.Beginn_Periode <=p.EndeProjekt)
- Bearbeitet Joerg_x Freitag, 13. Dezember 2019 20:58
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 20. Dezember 2019 13:14
- Als Antwort markiert Thorsten Schröer Freitag, 20. Dezember 2019 13:20
-
Vielen Dank Joerg_x für Deine ausfürliche Antwort.
Ich habe gerade Deinen Code mal versucht und bekomme direkt 2 out-of-range Fehler in Zeile 28 und 33.
"The conversion of a varchar data type to a datetime data type resulted in an out-of-range value."
Ich versuche es mal zu lösen, muss aber erst einmal Deinen Code analysieren
Thorsten Schröer Dipl-Inform (FH) - EDV, Beratung & Service - double-D-IT -Office- / Information system support Bismarckstraße 18a Germany-12169 Berlin Steglitz phone: +49-(0)30-303286770 fax: +49-(0)30-303286779
- Bearbeitet Thorsten Schröer Dienstag, 17. Dezember 2019 07:49
-
Hallo Thorsten,
vermutlich hast Du andere Spracheinstellungen.
Ergänze bitte den Code als erste Zeile:
SET dateformat dmy;
Schönen Tag.
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 20. Dezember 2019 13:14
- Als Antwort markiert Thorsten Schröer Freitag, 20. Dezember 2019 13:20
-
Habe ich ausprobiert. Das ändert nichts
Thorsten Schröer Dipl-Inform (FH) - EDV, Beratung & Service - double-D-IT -Office- / Information system support Bismarckstraße 18a Germany-12169 Berlin Steglitz phone: +49-(0)30-303286770 fax: +49-(0)30-303286779
-
Ich nehme es zurück. Es funktioniert.
Vielen Dank
Thorsten Schröer Dipl-Inform (FH) - EDV, Beratung & Service - double-D-IT -Office- / Information system support Bismarckstraße 18a Germany-12169 Berlin Steglitz phone: +49-(0)30-303286770 fax: +49-(0)30-303286779