| 

.NET C# Java Javascript Exception

5
Guten Abend Zusammen,
hat Jemand von Euch eine Idee wie die Datumslücken mit TSQL aufgefüllt werden können sodass im Resultat auch der 2.1 sowie der 4.1 enthalten sind.

column1| column2 | columnDate
------------------------------
wert1 | wert2 | 01.01.2014
wert1 | wert2 | 03.01.2014
wert1 | wert2 | 05.01.2014

Danke & Gruss
Jorgen
News:
25.02.2014
Jorgen Schumann 1,6k 1 9
2 Antworten
3
Folgende Lösung benutze ich/wir. Das sieht auf den ersten Blick viel aus, ist aber aus unseren SQL-Liberys die ich mal vor ner weile erstellt habe, ist aber universeller einsetzbar. Wenn du möchtest kannst du es ja auf ein Statment reduzieren.

Erstmal das Beispiel:

DECLARE @t TABLE (column1 varchar(100), column2 varchar(100), columnDate date)
INSERT INTO @t VALUES
('wert1','wert2', '1.1.14'),
('wert1','wert2', '3.1.14'),
('wert1','wert2', '5.1.14')

SELECT DAYS.date,T.*
--min und max Date ermitteln
FROM (SELECT MIN(columnDate) MINd, MAX(columnDate) MAXd FROM @t) tmp
--tage zwischen min und max ermitteln
OUTER APPLY [bl].[fGetDays](MINd, MAXd, 'd') DAYS
--Daten dran joinen
left JOIN @t t ON t.columnDate = DAYS.date

Ergebnis:

date       column1    column2    columnDate
---------- ---------- ---------- ----------
2014-01-01 wert1 wert2 2014-01-01
2014-01-02 NULL NULL NULL
2014-01-03 wert1 wert2 2014-01-03
2014-01-04 NULL NULL NULL
2014-01-05 wert1 wert2 2014-01-05


Und hier die Funktionen.
Eine Erklärung kommt weiter unten.

CREATE FUNCTION [dbo].[fx_DateAdd](@Datepart VARCHAR(4), @Number INT, @Date DATETIME)  
RETURNS DATETIME AS
BEGIN
DECLARE @Result DATETIME
SELECT @Result =
CASE
--Day
WHEN @datepart = 'dd' OR @DatePart = 'd' THEN DATEADD(dd, @Number, @Date)

--Month
WHEN @datepart = 'mm' OR @DatePart = 'm' THEN DATEADD(mm, @Number, @Date)

--Week
WHEN @datepart = 'wk' OR @DatePart = 'ww' THEN DATEADD(wk, @Number, @Date)

--Year
WHEN @datepart = 'yy' OR @DatePart = 'yyyy' THEN DATEADD(yy, @Number, @Date)

--Quarter
WHEN @datepart = 'qq' OR @DatePart = 'q' THEN DATEADD(qq, @Number, @Date)

--Day of Year
WHEN @datepart = 'dy' OR @DatePart = 'y' THEN DATEADD(dy, @Number, @Date)

--Hour
WHEN @datepart = 'hh' THEN DATEADD(hh, @Number, @Date)

--Minute
WHEN @datepart = 'mi' OR @DatePart = 'n' THEN DATEADD(mi, @Number, @Date)

--Second
WHEN @datepart = 'ss' OR @DatePart = 's' THEN DATEADD(s, @Number, @Date)

--Millisecond
WHEN @datepart = 'ms' THEN DATEADD(ms, @Number, @Date)
END

RETURN @Result
END
GO

CREATE FUNCTION [dbo].[fx_DateDiff](@Datepart VARCHAR(4), @DATE1 DATETIME, @DATE2 DATETIME)
RETURNS int AS
BEGIN
DECLARE @Result int
SELECT @Result =
CASE
--Day
WHEN @datepart = 'dd' OR @DatePart = 'd' THEN DATEDIFF(dd, @DATE1, @DATE2)

--Month
WHEN @datepart = 'mm' OR @DatePart = 'm' THEN DATEDIFF(mm, @DATE1, @DATE2)

--Week
WHEN @datepart = 'wk' OR @DatePart = 'ww' THEN DATEDIFF(wk, @DATE1, @DATE2)

--Year
WHEN @datepart = 'yy' OR @DatePart = 'yyyy' THEN DATEDIFF(yy, @DATE1, @DATE2)

--Quarter
WHEN @datepart = 'qq' OR @DatePart = 'q' THEN DATEDIFF(qq, @DATE1, @DATE2)

--Day of Year
WHEN @datepart = 'dy' OR @DatePart = 'y' THEN DATEDIFF(dy, @DATE1, @DATE2)

--Hour
WHEN @datepart = 'hh' THEN DATEDIFF(hh, @DATE1, @DATE2)

--Minute
WHEN @datepart = 'mi' OR @DatePart = 'n' THEN DATEDIFF(mi, @DATE1, @DATE2)

--Second
WHEN @datepart = 'ss' OR @DatePart = 's' THEN DATEDIFF(ss, @DATE1, @DATE2)

--Millisecond
WHEN @datepart = 'ms' THEN DATEDIFF(ss, @DATE1, @DATE2)
END

RETURN @Result
END
GO

CREATE FUNCTION [dbo].[fGetFirstDay](@dat date, @datepart varchar(4))
RETURNS datetime AS begin
return dbo.fx_DateAdd(@datepart,dbo.fx_DateDiff(@datepart, 0, @dat),0)
END
GO

/* =============================================
Description: Erzeugt eine Liste an Tagen zwischen dem Start- und dem Zieldatum im angegebenen Intervall
Example:
1: Alle Tage zwischen dem 01.01.2012 und dem 01.01.2013
SELECT * FROM bl.fGetDays('01.01.2012', '01.01.2013', 'D') OPTION (MAXRECURSION 2000);
2: Alle ersten eines Monats zwischen dem 01.01.2012 und dem 01.01.2013
SELECT * FROM bl.fGetDays('01.01.2012', '01.01.2013', 'M') OPTION (MAXRECURSION 2000);
============================================= */
CREATE FUNCTION [bl].[fGetDays](@From DATE, @To DATE, @Interval CHAR(1))
RETURNS TABLE
AS
RETURN
(
WITH T(date)
AS
(
SELECT cast(dbo.fGetFirstDay(@From, @Interval) AS date)
UNION ALL
SELECT CAST(dbo.fx_DateAdd(@Interval,1, T.date) AS DATE) FROM T WHERE T.date < CAST(dbo.fGetFirstDay(@To, @Interval) AS DATE)
)
SELECT date FROM T
);
GO


Die Lösung basiert auf einer recursieven CTE. Dadurch das die [fGetDays] verschiedene Intervalle unterstützt und die DateAdd-Funktion und die DateDiff-Funktion keine Variabelen als Intervallparameter unterstützen musste ich die Funktionen [fx_DateAdd] und [fx_DateDiff] bauen um das zu kompensieren.
26.02.2014
Floyd 14,6k 3 9
Floyd 14,6k 3 9
1
Eine Lösungsskizze: erst mal eine Liste aller in Frage kommenden Dates erzeugen. Dabei hilft Dir hoffentlich http://stackoverflow.com/questions/510012/get-a-list-of-dates-between-two-dates . Dann alle Einträge der Liste durchgehen, und wenn Du für das betreffende Datum einen Eintrag in Deiner Tabelle hast, dann diesen nehmen, sonst einen generieren (sprich Werte für column1 und column2 "erfinden").
26.02.2014
Matthias Hlawatsch 13,2k 4 9

Stelle deine Sql-Frage jetzt!