2011-01-21 16 views
4

ありがとうございました。SQL ServerのSQLステートメントでの動的日付

私は、任意の年に始まり、決して終わらない(未来に行く)年のデータを比較し、最後に完了した月までの同じ期間(毎月のデータ2月1日まで表示されません)。 T-SQLを使用することはできません。 2008/01/01から日付を動的に生成するために次のクエリを再フォーマットする方法(またはすべての年にそれをやっているだけです)と、ハードコーディングを行わずに永遠に行く方法はありますか?

select 
     case 
     when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit) 
     end as [Accounts Receivable], 
     jdt1.refdate as [Posting Date] 
from jdt1 
    inner join oact on jdt1.account = oact.AcctCode 
where (oact.fathernum like '1%') 
      and 
      (jdt1.refdate between '2008/01/01' and dateadd(day, -1, '2008/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2009/01/01' and dateadd(day, -1, '2009/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2010/01/01' and dateadd(day, -1, '2010/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2011/01/01' and dateadd(day, -1, '2011/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2012/01/01' and dateadd(day, -1, '2012/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2013/01/01' and dateadd(day, -1, '2013/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2014/01/01' and dateadd(day, -1, '2014/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2015/01/01' and dateadd(day, -1, '2015/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2016/01/01' and dateadd(day, -1, '2016/' + cast(month(getdate()) as varchar(2)) + '/01') 
      or jdt1.refdate between '2017/01/01' and dateadd(day, -1, '2017/' + cast(month(getdate()) as varchar(2)) + '/01')) 

group by oact.fathernum, jdt1.refdate 

問題を解決するストアドプロシージャでT-SQLを使用した再定式化で手を携えようとする人はいませんか?日付の上限は、動的である限り、常に現在の年にすることができます。 datesetsを生成し、それに参加する番号テーブルと

+1

このSQL Server 2005以上ですか? – RichardTheKiwi

+0

@cyberwiki - あり – m7d

答えて

2

は、以下のTSQLを示し、この作品?:ようsomethignだろ日間のシーケンスのためにそれをん動的カレンダーテーブルを構築する方法。 表示されているクエリは、ピボット日付を毎年変更しますが、さらに特定の年にカレンダーの開始日を修正する方法が示されています。

select 
     case 
     when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit) 
     end as [Accounts Receivable], 
     jdt1.refdate as [Posting Date] 
from jdt1 
inner join oact on jdt1.account = oact.AcctCode 

inner join (select 
    FirstDayOfYear =DATEADD(m,datediff(m,0,getdate())-MONTH(getdate())+1,0), 
    FirstDayOfMonth =DATEADD(m,datediff(m,0,getdate()),0)) D 
inner join master..spt_values v on v.type='P' 
    and v.number between 0 and 500 -- is 500 years enough? max=2047 from this table 
    on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear) 
    and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth) 

where (oact.fathernum like '1%') 
group by oact.fathernum, jdt1.refdate 

選択もで

inner join (select 
    FirstDayOfYear =DATEADD(m,datediff(m,0,getdate())-MONTH(getdate())+1,0), 
    FirstDayOfMonth =DATEADD(m,datediff(m,0,getdate()),0)) D 

という名前の通り2ピボット日は(**current year**の最初の日であり、現在の月の最初の日、2つのピボット日付の単一のレコードを作成します今年)。あなたは**specific**年の最初の日と月(当月)の最初の日を必要とするが、同じ特定の年に、あなたは

select 
    FirstDayOfYear =cast('20080101' as datetime), 
    FirstDayOfMonth =dateadd(m,month(getdate())-1,'20080101') 

(例えば、2008-JAN-01用)これ以下のバリエーションを使用することができる場合ピボット日付と組み込みの数値シーケンスを使用して、ピボット日付に1年ごとに徐々に追加します(今年は0を加算します)。

inner join master..spt_values v on v.type='P' 
    and v.number between 0 and 500 
    on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear) 
    and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth) 

も注意してくださいその代わりに

date between A and B 

は、私は通常、Bは、時刻情報が含まれているか否かに動作

date >= A and date < B+1 

好みます。あなたの質問には関係ありませんが、一貫性のための良い習慣です。

+0

印象深い、ありがとう!あなたはその問題をどのように処理するかを知るために冷静になります。そして、500年は十分であるはずです。 ) – m7d

+0

申し訳ありませんが、あなたのニックが間違っているので、キウイの代わりにウィキを見たことがあります。 – m7d

+0

@cyberkiwi - これはきちんとした解決策であり、私はそれに多くの用途を見出すことができますが、毎年新しい年が始まる前から常に始まる年を保つ方法はありますか?私は本当に2008年からしたい。それは毎年の同じ期間を正確に比較しています。私はそれを2008年の最初の年を修正するために修正する方法を見つけ出しておらず、その後のすべての年を比較しています。言い換えれば、2008年以降に始まるすべての年の同じ期間のデータを無期限に同時に設定する必要があります。 1月1日から21日まで、2008年1月1日から1月21日まで、など。 – m7d

2

スタート

このSO question

+0

また:http:// stackoverflow。com/questions/1478951/tsql-generate-a-incrementing-datesの日付 –

+0

リンクありがとうございましたgbn! – m7d

1

YEAR(jdt1.refdate) between 2008 and 2017 
    and 
MONTH(jdt1.refdate) < MONTH(getdate()) 
+0

それはインデックス利用のためにひどいです – RichardTheKiwi

+0

ですか?どうして? さらに重要なのは、恐ろしいことでしょうか? –

+0

最初の部分を見つけ出すためには、int値を返すために 'all'レコード全体にYEAR()を実行する必要があります。 'jdt1.refdate'に対してテストする適切に構成された日付範囲は、データの1/12しか収集する必要がありません。 – RichardTheKiwi

1

は、SQL Server 2005+を使用している場合、あなたは、単にその場でカレンダーを構築することができます。このソリューションで

With MaxDate As 
    (
    Select Max(refdate) As [Date] 
    From jdt1 
    ) 
    , Calendar As 
    (
    Select Cast(Cast(Year(GetDate())As char(4)) + '0101' As datetime) As [StartDay] 
     , DateAdd(d, -1, Cast(Cast(Year(GetDate()) + 1 As char(4)) + '0101' As datetime))As [EndDay] 
    Union All 
    Select DateAdd(yyyy, 1, [StartDay]) 
     , DateAdd(yyyy, 1, [EndDay]) 
    From Calendar 
     Join MaxDate 
      On Year(DateAdd(yyyy, 1, [EndDay])) <= Year(MaxDate.[Date]) 
    ) 
Select ... 
From Calendar As C 
    Join jdt1 
     On jdt1.refdate Between C.StartDay And C.EndDay 
    Join oact 
     On oact.AcctCode = jdt1.account 
Where oct.fathernum Like '%1' 
Group By oact.fathernum, jdt1.refdate  
Option (MaxRecursion 0); 

を、私は、今日の年から始まり、最後​​の年に出て拡大しました。

+0

シュート、だから私は2つの答えを授与させません。まあ、これも素晴らしい解決策です。ありがとう! – m7d