Zwischen Datumswerten Samstag und Sonntag filtern

ny_unity

SQL-Guru
Beiträge
185
Hallo zusammen,

ich habe in einer Tabelle zwei Datumswerte stehen, die geben von bis an.

Ich möchte die Anzahl der Tage zwischen von und bis OHNE Samstag und ohne Sonntag ermitteln.

Als Datenbank stände Firebird oder M$SQL zur Verfügung.

Hat jemand einen Lösungsvorschlag?

Danke,

Erik
 
Werbung:
Schnellschuß:

Code:
test=*# select * from demo;
 id |    von     |    bis     
----+------------+------------
  1 | 2020-07-01 | 2020-07-08
(1 row)
test=*# select id, von, bis, count(*) as werktage from demo left join lateral (select * from generate_Series(von,bis,'1day'::interval)) d(d) on (extract(dow from (d.d)) between 1 and 5) group by id, von, bis;
 id |    von     |    bis     | werktage
----+------------+------------+----------
  1 | 2020-07-01 | 2020-07-08 |        6
(1 row)
 
Wobei halt Werktage nicht unbedingt Mo-Fr sein muss, erst recht nicht wenn Feiertage berücksichtigt werden sollen. Oft gibt es in ERP-Datenbanken dafür eigene Kalendertabellen, die man joinen kann.
 
Wobei halt Werktage nicht unbedingt Mo-Fr sein muss, erst recht nicht wenn Feiertage berücksichtigt werden sollen. Oft gibt es in ERP-Datenbanken dafür eigene Kalendertabellen, die man joinen kann.

Mag sein, gewünscht war aber: "Ich möchte die Anzahl der Tage zwischen von und bis OHNE Samstag und ohne Sonntag ermitteln.".
 
Ein etwas Code-intensiver aber recht universeller Weg wäre:

1) die Zeiträume in Datensatz pro Tag zu zerlegen, z.B. mit CTE
2) z.B. mit day of week zu jedem Datum bestimmen um welchen Wochentag es sich handelt (Vorsicht: Je nach Ländereinstellung ist tatsächlich nicht Montag immer gleich Tag 1)
3) die gewünschten Tage aggregieren / zählen.

Ich wollte das jetzt nicht passend bauen aus Zeitgründen aber du bist ja vom Fach :) Ich habe hier ein Beispiel in dem Mengen auf Teilzeiträume aufgeteilt werden, die Berechnung kannst du aber ignorieren. Es passieren aber genau die drei genannten Schritte.
Code:
WITH tabelle(pauftrag,start,ende,menge) AS (
    SELECT 200,cast('2018-06-12' AS DATE),cast('2018-06-15' AS DATE),400 UNION ALL
    SELECT 201,'2018-06-13','2018-06-20',333 UNION ALL
    SELECT 202,'2018-06-14','2018-06-27',1500 UNION ALL
    SELECT 203,'2018-07-05','2018-07-06',100
    ), t1(pauftrag,start,ende,menge) AS (
    SELECT    tabelle.pauftrag,
            tabelle.start,
            tabelle.ende,
            tabelle.menge
    FROM    tabelle
    UNION ALL
    SELECT    t1.pauftrag,
            dateadd(day,1,t1.start),
            t1.ende,
            t1.menge
    FROM    t1
    WHERE    dateadd(day,1,t1.start) <= t1.ende
    ), t2(pauftrag,start,kw,menge) AS (
    SELECT    t1.pauftrag,
            convert(DATE,dateadd(week,0,dateadd(day,1-datepart(dw,t1.start),datediff(day,0,t1.start)))),
            datepart(week,t1.start),
            (    CASE
                WHEN    t1.menge / sum(count(*)) OVER (PARTITION BY t1.pauftrag) * sum(count(*)) OVER (PARTITION BY t1.pauftrag) = t1.menge
                OR        datepart(week,t1.start) < max(datepart(week,t1.start)) OVER (PARTITION BY t1.pauftrag)
                THEN    /*Das hier ist die eigentliche Berechnung der anteiligen Menge*/ t1.menge / sum(count(*)) OVER (PARTITION BY t1.pauftrag) * count(*)
                ELSE    /*Hier wird auf die letzte KW mit  anteiliger Menge der Restbetrag aufgeschlagen*/ t1.menge / sum(count(*)) OVER (PARTITION BY t1.pauftrag) * count(*) +
                        t1.menge - t1.menge / sum(count(*)) OVER (PARTITION BY t1.pauftrag) * sum(count(*)) OVER (PARTITION BY t1.pauftrag)
                END )
    FROM    t1
    WHERE    datepart(dw,t1.start) BETWEEN 1 AND 5
    GROUP BY t1.pauftrag,dateadd(week,0,dateadd(day,1-datepart(dw,t1.start),datediff(day,0,t1.start))),datepart(week,t1.start),t1.menge
    )
SELECT    t2.pauftrag,
        --Das ist der gesammte Zeitraum, wird einfach durch einen Join der originären Tabelle wieder als Spalten dazu geholt
        t3.start,
        t3.ende,
        --Das ist nur der Zeitraum auf den der berechnete Anteil entfällt
        (    CASE
            WHEN    datepart(week,t3.start) = t2.kw
            THEN    t3.start
            ELSE    t2.start
            END ) AS start_teilzeitraum,
        (    CASE
            WHEN    datepart(week,t3.ende) = t2.kw
            THEN    (CASE WHEN datepart(dw,t3.ende) > 5 THEN dateadd(day,(datepart(dw,t3.ende)*-1+5),t3.ende) ELSE t3.ende END)
            ELSE    dateadd(day,5,t2.start)
            END ) AS ende_teilzeitraum,
        t2.kw,
        t2.menge
FROM    t2
INNER JOIN tabelle t3
ON        t2.pauftrag = t3.pauftrag
"tabelle" liefert Testdatensätze, t1 zerlegt die Zeiträume mit CTE, t2 bestimmt in diesem Fall die KW, du musst nur den Wochentag bestimmen das ist einfacher. Dann zählst du die Tage.
 
Werbung:
Hallo @ukulele

danke für den aufwendigen Lösungvorschlag und sorry für die verspätete Antwort, war im Urlaub.

Ich schaue mir den Lösungsansatz im Laufe der Woche an und werde berichten...

MfG

Erik
 
Zurück
Oben