私は変更できない従来のテーブルを持っています。 その中の値は、従来のアプリケーションから変更できます(アプリケーションも変更できません)。 新しいアプリケーション(新しい要件)からテーブルへのアクセスが多いため、私はうまくいけばクエリをスピードアップする一時テーブルを作成したいと思います。テーブルの正規化
実際の要件は、XからYまでの営業日数を計算することです。たとえば、2001年1月1日から2004年12月24日までのすべての営業日をお知らせください。 (土曜日と日曜日だけではありません)
一時テーブルは、ユーザーがこのクエリの画面を入力するたびに.NETプログラムから作成されます複数回、異なる値で、テーブルが一度作成されるので)、私はできるだけ早くそれをしたいと思います。以下のアプローチは1秒以内に実行されますが、私は小さなデータセットでテストしましたが、おそらく最初のクエリのオーバヘッドであるにもかかわらず、UIにはあまり役に立ちません。
はレガシーテーブルには、次のようになります。
CREATE TABLE [business_days](
[country_code] [char](3) ,
[state_code] [varchar](4) ,
[calendar_year] [int] ,
[calendar_month] [varchar](31) ,
[calendar_month2] [varchar](31) ,
[calendar_month3] [varchar](31) ,
[calendar_month4] [varchar](31) ,
[calendar_month5] [varchar](31) ,
[calendar_month6] [varchar](31) ,
[calendar_month7] [varchar](31) ,
[calendar_month8] [varchar](31) ,
[calendar_month9] [varchar](31) ,
[calendar_month10] [varchar](31) ,
[calendar_month11] [varchar](31) ,
[calendar_month12] [varchar](31) ,
misc.
)
毎月31文字、および任意の休日(土曜日+日曜日+祝日)各半日が「H」とマークされているXでマークされてい。例えば、それは次のようになりますよりも月が、木曜日に開始した場合(木+金曜の平日、土曜日+日曜日はX印):
' XX XX ..'
私はそう見えるように新しいテーブルが欲しい:
temporary-を作成します。これまでで私がやってしまった、create table #Temp (country varchar(3), state varchar(4), date datetime, hours int)
そして、私は(以前のクエリからのXまたはHでマークされた)のみオフになっている日間の行を持っているしたいと思います
中間テーブル、これは次のようになります:
create table #Temp_2 (country_code varchar(3), state_code varchar(4), calendar_year int, calendar_month varchar(31), month_code int)
を移入するために、私は、各行が処理された後、私は、#Temp_2内のすべての行をループループを持っているよりも基本的には労働組合のはCalendar_Minute、calendar_month2、calendar_month3など
組合を持っています#Temp_2から削除されます。 行を処理するために、1〜31のループがあり、部分文字列(calendar_month、counter、1)がXまたはHのいずれかでチェックされます。この場合、#Tempテーブルへの挿入があります。
Declare @country_code char(3)
Declare @state_code varchar(4)
Declare @calendar_year int
Declare @calendar_month varchar(31)
Declare @month_code int
Declare @calendar_date datetime
Declare @day_code int
WHILE EXISTS(SELECT * From #Temp_2) -- where processed = 0)
BEGIN
Select Top 1 @country_code = t2.country_code, @state_code = t2.state_code, @calendar_year = t2.calendar_year, @calendar_month = t2.calendar_month, @month_code = t2.month_code From #Temp_2 t2 -- where processed = 0
set @day_code = 1
while @day_code <= 31
begin
if substring(@calendar_month, @day_code, 1) = 'X'
begin
set @calendar_date = convert(datetime, (cast(@month_code as varchar) + '/' + cast(@day_code as varchar) + '/' + cast(@calendar_year as varchar)))
insert into #Temp (country, state, date, hours) values (@country_code, @state_code, @calendar_date, 8)
end
if substring(@calendar_month, @day_code, 1) = 'H'
begin
set @calendar_date = convert(datetime, (cast(@month_code as varchar) + '/' + cast(@day_code as varchar) + '/' + cast(@calendar_year as varchar)))
insert into #Temp (country, state, date, hours) values (@country_code, @state_code, @calendar_date, 4)
end
set @day_code = @day_code + 1
end
delete from #Temp_2 where @country_code = country_code AND @state_code = state_code AND @calendar_year = calendar_year AND @calendar_month = calendar_month AND @month_code = month_code
--update #Temp_2 set processed = 1 where @country_code = country_code AND @state_code = state_code AND @calendar_year = calendar_year AND @calendar_month = calendar_month AND @month_code = month_code
END
[編集コードを追加]私はSQLの専門家ではないですので、私は私のアプローチにいくつかの入力、および多分より良いアプローチの提案を取得したいのですが。
一時テーブルを持った後、私は(日付はテーブルから来ることになる)行うことを計画しています:
select cast(convert(datetime, ('01/31/2012'), 101) -convert(datetime, ('01/17/2012'), 101) as int) - ((select sum(hours) from #Temp where date between convert(datetime, ('01/17/2012'), 101) and convert(datetime, ('01/31/2012'), 101))/8)
テーブルを正規化するの溶液に加えて、私は今のところ実装され、他の解決策は、あります現在のテーブルをスキャンして営業日を取得するというこのすべてのロジックを実行する関数です。それはかなり速く実行されますが、結果を得るために単純なクエリを追加できるのであれば、私は関数を呼び出すことを躊躇しています。
(私は現在、MSSQLでこれをしようとしているが、私は、Sybase ASEとOracleのために同じことを行う必要があります)
ループコードを送信します。 – Paparazzi
あなたは3つの異なるDBMSで動作するようにクエリが必要だと言っていますか? –
mssql + sybase + oracleで同じクエリを実行する必要はありません。他のデータベースと同様のものが必要です。誰かがそれらのいずれかの提案をすることができ、私はそのデータベースから始め、mssqlにバックポートします。 – Alex