Wie in vielen der bereits gegebenen wunderbaren Antworten erwähnt (oder zumindest angedeutet), ist dieses Problem leicht zu lösen, sobald Sie eine Reihe von Zahlen haben, mit denen Sie arbeiten können.
Hinweis: Das Folgende ist T-SQL, aber es ist einfach meine spezielle Implementierung allgemeiner Konzepte, die hier und im Internet insgesamt bereits erwähnt wurden. Es sollte relativ einfach sein, den Code in den Dialekt Ihrer Wahl umzuwandeln.
Wie? Betrachten Sie diese Abfrage:
SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;
Das obige ergibt den Datumsbereich 1/22/0001 - 1/27/0001 und ist äußerst trivial. Es gibt 2 wichtige Informationen in der obigen Abfrage: das Startdatum von 0001-01-22
und die Offset von 5
. Wenn wir diese beiden Informationen kombinieren, haben wir offensichtlich unser Enddatum. Bei zwei Daten kann die Generierung eines Bereichs folgendermaßen unterteilt werden:
Finden Sie den Unterschied zwischen zwei angegebenen Daten (dem Versatz) ganz einfach:
-- Returns 125
SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))
Durch die Verwendung ABS()
hier wird sichergestellt, dass die Datumsreihenfolge irrelevant ist.
Generieren Sie eine begrenzte Anzahl von Zahlen, auch einfach:
-- Returns the numbers 0-2
SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM(SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A')
Beachten Sie, dass es uns eigentlich egal ist, was wir hier auswählen FROM
. Wir brauchen nur einen Satz, mit dem wir arbeiten können, damit wir die Anzahl der Zeilen darin zählen können. Ich persönlich benutze einen TVF, einige verwenden einen CTE, andere verwenden stattdessen eine Zahlentabelle, Sie haben die Idee. Ich befürworte die Verwendung der leistungsstärksten Lösung, die Sie auch verstehen.
Die Kombination dieser beiden Methoden löst unser Problem:
DECLARE @date1 DATE = '9001-11-21';
DECLARE @date2 DATE = '9001-11-23';
SELECT D = DATEADD(d, N, @date1)
FROM (
SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM (SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A') S
) Numbers
WHERE N <= ABS(DATEDIFF(d, @date1, @date2));
Das obige Beispiel ist schrecklicher Code, zeigt aber, wie alles zusammenkommt.
Mehr Spaß
Ich muss so etwas oft machen, also habe ich die Logik in zwei TVFs zusammengefasst. Der erste generiert einen Zahlenbereich und der zweite verwendet diese Funktion, um einen Datumsbereich zu generieren. Die Mathematik besteht darin, sicherzustellen, dass die Eingabereihenfolge keine Rolle spielt und ich den gesamten Bereich der verfügbaren Zahlen verwenden wollte GenerateRangeSmallInt
.
Die folgende Funktion benötigt ~ 16 ms CPU-Zeit, um den maximalen Bereich von 65536 Daten zurückzugeben.
CREATE FUNCTION dbo.GenerateRangeDate (
@date1 DATE,
@date2 DATE
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
SELECT D = DATEADD(d, N + 32768, CASE WHEN @date1 <= @date2 THEN @date1 ELSE @date2 END)
FROM dbo.GenerateRangeSmallInt(-32768, ABS(DATEDIFF(d, @date1, @date2)) - 32768)
);
GO
CREATE FUNCTION dbo.GenerateRangeSmallInt (
@num1 SMALLINT = -32768
, @num2 SMALLINT = 32767
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
WITH Numbers(N) AS (
SELECT N FROM(VALUES
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 16
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 32
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 48
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 64
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 80
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 96
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 112
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 128
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 144
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 160
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 176
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 192
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 208
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 224
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 240
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 256
) V (N)
)
SELECT TOP(ABS(CAST(@num1 AS INT) - CAST(@num2 AS INT)) + 1)
N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) + CASE WHEN @num1 <= @num2 THEN @num1 ELSE @num2 END - 1
FROM Numbers A
, Numbers B
);