User Tools

Site Tools


mysql:createalldateofmonth

[MySQL] Virtuelle Tabelle mit allen Daten eines Monats

Aufgabenstellung

Ich will für jeden Tag im Monat eine Zeile haben in der das Datum steht. Es liegt keine Tabelle zugrunde.

mydate
2012-11-01
2012-11-02
2012-11-29
2012-11-30

Lösungen

Ähnlich, jedoch einfacher wie [MySQL] Virtuelle Tabelle mit allen Daten im Jahr ist es, alle Daten eines Monats zu ermitteln

Und natürlich führen viele Wege nach Rom. Ich habe hier mal 2 Beispiele wie man sowas bewerkstelligen könnte. In beiden ermittle ich alle Tage im November 2012. Das Reusltat ist bei beiden dasselbe

Lösung 1: Tagesnummer hochzählen, ein Datumsstring zusammensetzen und parsen

Mit einem Zähler (@day_in_month) für jeden Tag das Datum erstellen

SQL Statement

SELECT  
    days_in_month.mydate
FROM
    (    
        SELECT
            vars.selected_month,
            -- Tag hochzählen
            @day_in_month := @day_in_month + 1 AS day_in_month,
            -- Ein Datumsstring zusammensetzen und als Datum parsen
            STR_TO_DATE(CONCAT_WS('-',@day_in_month, vars.selected_month, vars.selected_year), '%d-%m-%Y') AS mydate
        FROM
        -- 6^2 Zeilen erstellen: Also 36.
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d1,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d2,
            -- Variablen instanzieren. Hier der November 2012
            (SELECT @day_in_month :=0, 2012 AS selected_year, 11 AS selected_month) AS vars
    ) AS days_in_month
WHERE
    -- Nur die gültigen Tage auswählen. Zur erinnerung, wir haben 36 Zeilen....
    MONTH(days_in_month.mydate) = days_in_month.selected_month;

Erklärbär

[Grid] Zeilen zur Verfügung stellen

Ich erstelle 36 virtuelle Zeilen. Dazu nehme ich 2 UNION-Queries mit je 6 Einträgen die ich unverknüpft zusammenführe.

Grid
-- [GRID]
-- 6^2 Zeilen erstellen: Also 36.
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d2,
[Vars] Variablen initialisieren

Dann erstelle ich ein weiteres Subquery um die Variablen zu setzen

Vars
-- VARS]
SELECT
    @day_in_month :=0,
-- <Monatsdefinition> --
    2012 AS selected_year,
    11 AS selected_month
-- </Monatsdefinition> --
[Calc] Berechnen der Tage

Diese werden nun zusammengeführt. Somit habe ich die Initialisierten Variablen und 36 Zeilen. Damit lässt sich wunderschön arbeiten

Calc
-- [CALC]
SELECT
    vars.selected_month,
    -- Tag hochzählen
    @day_in_month := @day_in_month + 1 AS day_in_month,
    -- Ein Datumsstring zusammensetzen und als Datum parsen
    STR_TO_DATE(CONCAT_WS('-',@day_in_month, vars.selected_month, vars.selected_year), '%d-%m-%Y') AS mydate
FROM
    [GRID],
    [VARS]

Zuerst erhöhe ich immer @day_in_month um 1. Anschliessend setze ich mit dem Jahr, Monat und dem @day_in_month einen Datumsstring zusammen: ##[DATE_STRING] = CONCAT_WS('-',@day_in_month, vars.selected_month, vars.selected_year)## DIeser wird nun noch in ein gültiges Datum gewandelt ##STR_TO_DATE([DATE_STRING], '%d-%m-%Y')##

ungültige Ausfiltern

Am Schluss haben wir natürlich das Problem, dass wir 36 Zeilen haben. Wir brauchen aber nu 28 bis 31, je nach Monat. STR_TO_DATE() kann mit einem Datumsstring '35-11-2012' nix anfangen und gibt da darum NULL zurück. Um nun sicher zu sein, dass ich nur Tage meines ausgewählten Monat habe, setzen ich das ganze nochmals in ein Query und vergleiche den Monat des ermittelten Tages mit dem selektierten Monat.

SELECT  
    days_in_month.mydate
FROM
    [CALC] AS days_in_month
WHERE
    -- Nur die gültigen Tage auswählen. Zur erinnerung, wir haben 36 Zeilen....
    MONTH(days_in_month.mydate) = days_in_month.selected_month;

Lösung 2: Das Datum hochrechnen

Und zum zeigen das viele Wege nach Rom führen. Das Datum des letzten tages vor dem Monat ermitteln und dann für jeden Tag ein Tag dazurechnen.

SQL-Statement

SELECT  
    days_in_month.mydate
FROM
    (    
        SELECT
            vars.selected_month,
            -- Tag im Monat hochzählen
            @act_date := DATE_ADD(@act_date, INTERVAL 1 DAY) AS mydate
        FROM
            -- 6^2 Zeilen erstellen: Also 36.
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d1,
            (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) AS d2,
            -- Variablen instanzieren
            (
                SELECT @selected_year  := 2012, @selected_month := 11       AS selected_month,
                    -- Letzter Tag im Vormonat ermitteln
                    @act_date := DATE_SUB(STR_TO_DATE(CONCAT_WS('-',1, @selected_month, @selected_year), '%d-%m-%Y'), INTERVAL 1 DAY)               
            ) AS vars
    ) AS days_in_month
WHERE
    -- Nur die gültigen Tage auswählen. Zur erinnerung, wir haben 36 Zeilen....
    MONTH(days_in_month.mydate) = days_in_month.selected_month;

Erklärbär

[Grid] Zeilen zur Verfügung stellen

Das [GRID] ist dasselbe wie bereits im ersten Beispiel

[Vars] Variablen initialisieren

Hier ist ein wenig mehr. Ich erstelle aus den Parameter gleich das Datum des letzten Tages des Vormonates. Dazu setze ich wieder ein Datum-String auf den ersten des Monats und zieh 1 Tag ab. Somit erhalte ich den letzten Tag des Vormonats in der Variable @act_date.

Vars
-- [VARS]
SELECT 
    -- <Monatsdefinition> --
    @selected_year  := 2012, 
    @selected_month := 11       AS selected_month,
    -- </Monatsdefinition> --
    @day_in_month :=0, 
    -- Letzter Tag im Vormonat ermitteln
    @act_date := DATE_SUB(STR_TO_DATE(CONCAT_WS('-',1, @selected_month, @selected_year), '%d-%m-%Y'), INTERVAL 1 DAY)               
[Calc] Berechnen der Tage

Dafür ist die Berechnung nachher umso einfacher. Einfach jedesmal 1 Tag zu @act_date dazurechnen.

Calc
-- [CALC]
SELECT
    vars.selected_month,
    -- Tag im Monat hochzählen
    @act_date := DATE_ADD(@act_date, INTERVAL 1 DAY) AS mydate
FROM
    [GRID],
    [VARS]
ungültige Ausfiltern

Das funktioniert genauso wie beim ersten Beispiel.

mysql/createalldateofmonth.txt · Last modified: 12.12.2013 09:22:30 (external edit)