كيفية الحصول على جميع التواريخ بين الشهر الحالي والشهرين الماضيين

أحاول الحصول على جميع التواريخ الموجودة بين الشهر الحالي والشهرين الماضيين.

على سبيل المثال: اليوم 10-01-2019 مع برنامج نصي sql ، سوف أحصل على جميع التواريخ بين 2018-10-01 و 2019-01-31.

with cte as
  (
  select getdate() as   n
  union all
  select  dateadd(DAY,-1,n) from cte where month(dateadd(dd,-1,n)) < month(DATEADD(month, -3, getdate())) --and month(DATEADD(month, 0, getdate()))
   union all
  select  dateadd(DAY,-1,n) from cte where month(dateadd(dd,-1,n)) > month(DATEADD(month, 0, getdate()))
  )
  select * from cte

انا حصلت

error msg 530، Level 16، State 1، Line 1   انتهى البيان. تم استنفاد الحد الأقصى للعنود 100 قبل اكتمال العبارة.

1
وأضاف المؤلف DavidG, مصدر

5 إجابة

Recursion is not a good approach to this. Performance wise using a recursive cte to increment a counter is the same thing as a cursor. http://www.sqlservercentral.com/articles/T-SQL/74118/

وهناك نهج أفضل بكثير هو أن تقوم هذه المجموعة على أساس. لهذه المهمة ، يعد جدول رصيد مثاليًا. هنا هي مقالة رائعة حول الموضوع.

احتفظ بجدول رصيد كطريقة عرض في نظامي. إنه سريع البرق مع قراءة صفر.

create View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally
GO

ثم لشيء مثل هذه المشكلة فمن السوبر سهلة الاستخدام. هذا سوف ينتج نفس النتائج بدون حلقات.

declare @endDate datetime = '2019-01-31'
    , @tmpDate datetime = '2018-10-01'

select dateadd(day, t.N - 1, @tmpDate)
from cteTally t
where t.N - 1 <= DATEDIFF(day, @tmpDate, @endDate)
3
وأضاف
إجابة رائعة مع مثال جيد لجدول الرصيد. شكرا لمشاركتك هذا معنا.
وأضاف المؤلف Eray Balkanli, مصدر
ردًا علىErayBalkanli
وأضاف المؤلف Sean Lange, مصدر
الجواب الوحيد (في وقت التعليق) الذي لا يستخدم rCTE ، أو (أسوأ من ذلك) حلقة WHILE . هذه هي الإجابة الصحيحة هنا.
وأضاف المؤلف Larnu, مصدر

سيعمل هذا حسب إصدار SQL Server الخاص بك.

with cte as
  (
     select cast(getdate() as date) as   n
     union all
     select  dateadd(DAY,-1,n) from cte where dateadd(DAY,-1,n) > (select eomonth(cast(dateadd(month,-4,getdate()) as date)))
  )
  select * 
  from cte
  order by n desc
  option (maxrecursion 200)
2
وأضاف

يمكنك استخدام جدول مؤقت لهذا الغرض. مع حلقة ، فقط قم بإضافة التواريخ التي تحتاجها إلى الجدول المؤقت. تحقق من الاستعلام أدناه:

create table #temp (thedate date)
declare @i int = 1
declare @tmpDate datetime = dateadd(month,-2,getdate())

while @tmpDate<=getdate()
begin
  insert into #temp
  values (@tmpDate)

  set @tmpDate = dateadd(day,1,@tmpDate)
end

select * from #temp

تعديل: بناء على تعليق OP ، استعلام جديد:

create table #temp (thedate date)
declare @i int = 1
declare @endDate datetime = '2019-01-31'
declare @tmpDate datetime = '2018-10-01'

while @tmpDate<[email protected]
begin
  insert into #temp
  values (@tmpDate)

  set @tmpDate = dateadd(day,1,@tmpDate)
end

select * from #temp
1
وأضاف
SeanLange أنت على حق ، ليس لديها أفضل أداء ولكن لمدة شهرين من العملية ، فهي سريعة ومفيدة للغاية.
وأضاف المؤلف Eray Balkanli, مصدر
ثم تعيينNewbieSQL تاريخ الانتهاء الخاص بك كـ 2019-01-31 بدلاً من استخدام getdate() وتعيين القيمة الأولى من tmpdate كـ 2018-10-01.
وأضاف المؤلف Eray Balkanli, مصدر
SeanLange لم أستخدمها مطلقًا ، دعني أراجعها وأتعلمها.
وأضاف المؤلف Eray Balkanli, مصدر
قامNewbieSQL بتحديث إجابتي.
وأضاف المؤلف Eray Balkanli, مصدر
الحلقات هنا ليست الطريقة الأكثر فعالية.
وأضاف المؤلف Sean Lange, مصدر
سيكون جدول الحصاد أكثر سهولة في الاستخدام. :)
وأضاف المؤلف Sean Lange, مصدر
جرب هذه المادة. sqlservercentral.com/articles/T-SQL/62867
وأضاف المؤلف Sean Lange, مصدر
أحصل على القيم من 2018-11-10 حتى 2019-01-10 لكن المطلب هو الحصول على التواريخ من 2018-10-01 (بداية الشهر) و 2019-01-31 (نهاية الشهر الحالي).
وأضاف المؤلف NewbieSQL, مصدر

أنت تضغط على الحد الأقصى للتكهن. زيادة ذلك كخيار:

with cte as
  (
  select getdate() as   n
  union all
  select  dateadd(DAY,-1,n) from cte where month(dateadd(dd,-1,n)) < month(DATEADD(month, -3, getdate())) --and month(DATEADD(month, 0, getdate()))
   union all
  select  dateadd(DAY,-1,n) from cte where month(dateadd(dd,-1,n)) > month(DATEADD(month, 0, getdate()))
  )
select * from cte
OPTION (MAXRECURSION 1000)
0
وأضاف
هذا لا يزال يضرب حد العودية ... والتكرار ليس هو النهج الأفضل هنا. هذا صرخ لجدول التقويم أو التقويم.
وأضاف المؤلف Sean Lange, مصدر
with cte as
  (
  select dateadd(month,1,dateadd(day, -1* day(getdate()) , cast(getdate() as date) )   ) n
  union all
  select  dateadd(day,-1,n) from cte where month(n)  + year(n) * 12 >= month(getdate())  + year(getdate()) * 12 -3
  ),
 final as (select * from cte except  select top 1 * from cte order by n)
select * from final order by n
OPTION (MAXRECURSION 1000)

أو لاستخدام dateadd فقط وتجنب ما عدا

with cte as
  (
  select dateadd(month,1,dateadd(day, -1* day(getdate()) , cast(getdate() as date) )   ) n
  union all
  select  dateadd(day,-1,n) from cte where n > dateadd(month,-3,dateadd(day , 1 - day(getdate()),cast(getdate() as date))) 
  )
select * from cte order by n
OPTION (MAXRECURSION 1000)
0
وأضاف