Daha önce verilen harika cevapların çoğunda belirtildiği (veya en azından belirtildiği gibi), çalışmak için bir dizi sayınız olduğunda bu sorun kolayca çözülür.
Not: Aşağıdakiler T-SQL'dir, ancak burada ve genel olarak internette bahsettiğim genel kavramları özel olarak benim uygulamam. Kodu seçtiğiniz lehçenize dönüştürmek nispeten basit olmalıdır.
Nasıl? Bu sorguyu düşünün:
SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;
Yukarıdaki tarih 1/22/0001 - 1/27/0001 tarih aralığını üretir ve son derece önemsizdir. : Yukarıdaki sorguda bilgilerin 2 anahtar parçaları vardır başlangıç tarihi arasında 0001-01-22
ve ofset arasında 5
. Eğer bu iki bilgiyi birleştirirsek, son tarihimiz açıktır. Böylece, iki tarih verildiğinde, bir aralık oluşturmak şu şekilde parçalanabilir:
Verilen iki tarih (ofset) arasındaki farkı bulun, kolay:
-- Returns 125
SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))
ABS()
Burada kullanılması tarih sırasının alakasız olmasını sağlar.
Sınırlı bir sayı kümesi oluşturun, ayrıca kolay:
-- 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')
FROM
Burada ne seçtiğimiz umrumda değil . Çalışmak için bir sete ihtiyacımız var, böylece içindeki satır sayısını sayıyoruz. Şahsen bir TVF kullanıyorum, bazıları CTE kullanıyor, diğerleri bunun yerine bir sayı tablosu kullanıyor, fikri anlıyorsunuz. Ben de sizin anladığınız en performanslı çözümü kullanmayı savunuyorum.
Bu iki yöntemi birleştirmek sorunumuzu çözecektir:
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));
Yukarıdaki örnek korkunç bir koddur, ancak her şeyin nasıl bir araya geldiğini gösterir.
Daha fazla eğlence
Bu tür şeyleri çok yapmam gerekiyor, bu yüzden mantığı iki TVF'ye kapsülledim. Birincisi bir dizi sayı üretir ve ikincisi bu işlevselliği bir tarih aralığı oluşturmak için kullanır. Matematik, giriş sırasının önemli olmadığından emin olmak ve mevcut sayıların tamamını kullanmak istediğimden emin olmaktır GenerateRangeSmallInt
.
Aşağıdaki işlev, maksimum 65536 tarih aralığını döndürmek için ~ 16ms CPU zaman alır.
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
);