2011-01-09 15 views
0

以下は、評価エンジンテーブルからの更新された保険料で毎月支払われた保険証券レコードを更新するためにvb.netで何ができるのかを示す擬似コードです。しかし、私はこれをSQL Serverデータベースのストアドプロシージャ内で実行できる必要があります。私が知る限り、2つのカーソル、外側のループ用と内側のループ用のカーソルを使用する必要があります。私の問題は、内側のカーソルを埋めるSQLクエリを構築するためには、Transact SQLの構文について十分な知識がないということです。ここでは擬似コードです:私は2つのカーソルを作成するよりも、これを行うには良い方法があると確信してvb.netで使用しているレコードセットのネストループをトランザクションSQLでどのようにレプリケートしますか?

Dim rsouter as ADODB.Recordset = New ADODB.Recordset 
Dim rsinner as ADODB.Recordset = New ADODB.Recordset 
Dim strSQL as string 
Dim Paycol as string 

‘ first of all open a recordset to get the records for updating 

Rsouter.open(Select area, [payment method], suminsured, scpremium from tblpolicy where [payment method] = ‘monthly’), CurrentProject.Connection 

‘ then loop through this outer recordset 

Do while not rsouter.eof 

‘ set the Paycol variable value to being a column name concatenated from the string “SC” and the value of the field “suminsured” from the open recordset, e.g. "SC12000" 

Paycol = ‘SC’ & rsouter.fields(‘suminsured’).value 

‘ now build the string to create the inner recordset 

strSQL = ‘Select area, ‘ & Paycol & ‘ as sc from re where area = ‘ & rsouter.fields(‘area’).value 

' the string should read something like; "select area, sc12000 from re where area = 5" 

‘ open the inner recordset against the query string 

Rsinner.open(strSQL), CurrentProject.Connection 

‘ update the outer recordset premium field with the value from the inner recordset 

Rsouter.fields(‘scpremium’).value = rsinner.fields(‘sc’).value 

‘ close the inner recordset 

Rsinner.close 

‘ commit the change to the outer recordset 

rsouter.update() 

‘ move to the next record in the outer recordset 

If not rsouter.eof then rsouter.movenext() 

loop 

‘ close the outer recordset 

rsouter.close() 

が、私のSQLは助けなしでそれを行うことができるのに十分強力ではありません。


YADS、あなたの答えのための

多くのおかげで、それは私が持っている問題を解決するための長い道のりを行きます。残念ながら、私の問題は私の元の要求で書いた擬似コードよりも少し複雑です。実際には、内側のカーソルから複数の値を取得して外側のカーソルに戻す必要があります。私は毎年のプレミアム、毎月のプレミアム、2週間ごとのプレミアム、週ごとのプレミアム、およびデビットプレミアムをreテーブルから取得し、それらのすべてを使用して外側のカーソルのポリシーテーブルレコードの対応するフィールドを更新する必要があります。あなたのコードが新しいプロシージャを作成し、カラム名と領域の一部を渡していることを理解しています。プロシージャを実行すると、渡された列の値が戻され、ポリシー表のその列の値を更新するために使用されます。

私は私が読むためにEXECステートメントを変更することができると思います:

EXEC ('select ' & @premiumColName & ' from re where re.area = ''' & @area & ''') 

私はその後、何度EXECステートメントを実行しますが、異なるカラム名にそれぞれの時間を渡すことができます。その後、各プレミアム列を順番に更新するために、SETステートメントを繰り返し実行する必要があります。

だから、私の次の質問は、これらは以下のとおりです。

  1. 私はGetPremium手順に私の外にカーソルがループするたびに作成およびドロップする必要がありますか?
  2. 更新ステートメントは更新するレコードをどのように知っていますか、または一致する領域を持つテーブルの(外部カーソルではなく)すべてのレコードを更新しますか?
  3. GetPremiumで要求されている列の内容を検証して、値をゼロに戻してから外側のカーソルのプレミアム列を更新する方法を確認するにはどうすればよいですか?

ダミアン、

私はあなたの助けのために非常に感謝しています。残念ながら私は他の誰かのVB6プログラムをVB.NETに変換しています。これを行う過程で、データストレージを設計した元のプログラマーは、元の6つのAccessデータベースを1つのSQL Serverデータベースに連結することに決めました。そうすることで、彼はいくつかのテーブルを再設計し、オリジナルの年次プレミアム、月額プレミアム、2週間ごとのプレミアム、週ごとのプレミアム、および口座引き落としプレミアムテーブルを、すべての列を別々に追加して1つのテーブルに連結しました。したがって、すべての年間プレミアム列は、プレフィックス 'AC'を持つ新しい評価エンジンテーブルに追加されます。すべての2週間のプレミアム列には接頭辞「FC」が付いています。私は彼が外部ソフトウェア供給者であり、プログラムとそのデータ構造に対する知的財産権を所有しているので、これがどのように機能するかを変えることはできません。私ができることは、可能な限りアドバイスし、VB.NET自身のスピードを上げず、当社の製品が必要なので、VBコード変換作業を引き受けます。

現在の非常に遅い更新プロセスのスピードアップを試みる方法として、私はVBプログラムのフォームを置き換えるストアドプロシージャを作成しようと努力してきました。これは現在、別々のデータベース、レートの変更については、ポリシーテーブルの既存のレコード(データベースの「コア」テーブルと呼ばれます)に適用されます。これは非常に非効率的であるだけでなく、月の最初の日にプログラムを開く最初の人は誰でも、コードを実行する前に更新フォームが待つ(時には数時間かかる)ことを意味します。さらに、誰も更新プロセスの実行中に何もできません。私は毎月1日に一晩実行するようにスケジュールすることができるようにストアドプロシージャを設定し、ポリシーを行くと、すべての既存の賃金にプレミアムの変更を適用するつもりこれを置き換えるために

。うまくいけば、これは、プログラムを使用して作業を行うことができる前に終日待機することを意味し、更新プロセス中に意図しない人の介入を防ぐことを意味します。

これまでのところ、2つのストアドプロシージャがあります。最初のものは 'UpdateAll'と呼ばれ、更新が必要なポリシーのみを使用して一時テーブルを埋めるためのコードが含まれています。現在、合計約103,000件のうち約6000件が更新されています。このテーブルは、次に、カーソルを埋めるように照会され、各レコードについて、収集された列の値を変数に入れる。私は、接頭辞 'AC'、 'FC'などをsuminsured列の値に連結し、結果の文字列を変数に代入することができます。だから、例えば、必要な年間プレミアム列を構築するためのコードは次のとおりです。私は今YADSが早く送らGetPremiumストアドプロシージャを少し変更したバージョンを呼び出すことができます行わこれにより

set @ansum = 'AC' + ltrim(str(@suminsured)) 

。これは出力変数を満たします。この変数は '@ansumval'という変数です。それを呼び出すためのコードは次のとおりです。

EXECUTE dbo.GetPremium @ansum, @area, @ansumval 

私はカーソルを閉じた後など、毎月、隔週、毎週政策、プレミアムの情報を更新するために、他の列ごとにこれを繰り返します。私はその後、tmpcore2テーブルに6000かそこらのレコードを新しいカーソル、およびループを開き、証明書なしにマッチしたレコードを更新するために、それぞれのいずれかを使用することができます。コアテーブル内(certno)とtmpcore2レコードのマッチング列からの値で、必要な列を更新します。この後、私はカーソルを閉じ、すべてが完了します。

これはテーブル結合を行うほど効率的ではありませんが、列名を動的に作成することができますし、更新値をチェックして正しい値を上書きしないようにすることもできます支払額はゼロです。各カーソルの作業ビットの簡略リストは以下の通りである。

open cursor1 

select * from tmpcore2 order by area 

Fetch Next From Cursor1 into @area, @HA, @cert, @status, @paymeth, @suminsured, @anprem, @monprem, @fortprem, @dprem, @wprem 

    While @@Fetch_status = 0 
     Begin 

      set @ansum = 'AC' + ltrim(str(@suminsured)) 
      set @mnsum = 'SC' + ltrim(str(@suminsured)) 
      set @ftsum = 'FN' + ltrim(str(@suminsured)) 
      set @dsum = 'DD' + ltrim(str(@suminsured)) 
      set @wksum = 'WK' + ltrim(str(@suminsured)) 

      EXECUTE GetPremium @ansum, @area, @ansumval 
      EXECUTE GetPremium @mnsum, @area, @mnsumval 
      EXECUTE GetPremium @ftsum, @area, @ftsumval 
      EXECUTE GetPremium @wksum, @area, @dsumval 
      EXECUTE GetPremium @dsum, @area, @wksumval 

      if @ansumval > 0 UPDATE tmpcore2 SET [Annual premium] = @ansumval 
      if @mnsumval > 0 UPDATE tmpcore2 SET [Monthly premium] = @mnsumval 
      if @ftsumval > 0 UPDATE tmpcore2 SET [Fortnightly premium] = @ftsumval 
      if @dsumval > 0 UPDATE tmpcore2 SET dpremium = @dsumval 
      if @wksumval > 0 UPDATE tmpcore2 SET wpremium = @wksumval 

-- loop through until all records updated 

close cursor1 

open cursor2 


select * from tmpcore2 order by certno 


Fetch Next From Cursor2 into @area, @HA, @cert, @status, @paymeth, @suminsured, @anprem, @monprem, @fortprem, @dprem, @wprem 

    While @@Fetch_status = 0 
     Begin 

      Update core 
       SET [annual premium] = @anprem, 
        [monthly premium] = @monprem, 
        [fortnightly premium] = @fortprem, 
        dpremium = @dprem, 
        wpremium = @wprem 
       WHERE certno = @cert 

-- loop through until all records updated 

     End 

close Cursor2 
+0

できる場合は、データベーススキーマを変更することを強くお勧めします。 SCを開始してからデータ値を持つ別の名前の列は存在してはいけません。余分な列は「suminsured」を表し、1つのsc列は検索された値を表す必要があります。それはまた、この現在のクエリのSQLを書くのが簡単になります。 –

答えて

2

ひとつのクエリ でそれを行うには良い方法は、これはあなたが何をしようとしてありませんでしょうか?

CREATE PROC GetPremium 
@premiumColName VARCHAR2(50), 
@area VARCHAR2(50) 
AS BEGIN 
EXEC ('SELECT sc' & @premiumColName & ' FROM re WHERE re.area = ''' & @area & '''') 
END  

    UPDATE tblpolicy 
    SET scpremium = EXECUTE GetPremium tblpolicy.suminsured, tblpolicy.area 
0

あなたが再テーブルを再構築するので、代わりに

CREATE TABLE re (
    area varchar(10) not null, 
    sc12000 int not null, 
    sc14000 int not null, 
    sc16000 int not null 
) 

のことができればあなたがするこれ​​を変更する必要があります

その後、suminsured = 12000のための3つのトウを(含まれています
CREATE TABLE re (
    area varchar(10) not null, 
    suminsured int not null, 
    sc int not null 
) 

、14000、16000)

これを1つのクエリとして書き直します。

UPDATE p 
SET 
    scpremium = re.sc, 
    /* set other columns as required */ 
FROM 
    tblpolicy p 
     inner join 
    re 
     on 
      p.area = re.area and 
      p.suminsured = re.suminsured 
WHERE 
    p.[payment method] = 'monthly' 

何らかの理由でreテーブルを変更できない場合は、私が示した2番目のテーブルのようなビューを作成し、代わりにそのテーブルを使用することができます。


私はまだあなたが良い、セットベースのSQLを書き、あなたの同僚は、データベース設計についての手掛かりを持っていることをふりをすることができますビューを構築する方がいいでしょうと思います。

CREATE TABLE dbo.re (
    area varchar(10) not null, 
    sc12000 int not null, 
    sc14000 int not null, 
    sc16000 int not null, 
    fc12000 int not null, 
    fc14000 int not null, 
    fc16000 int not null 
) 
go 
insert into dbo.re(area,sc12000,sc14000,sc16000,fc12000,fc14000,fc16000) 
select 'abc',1,2,3,4,5,6 union all 
select 'def',7,8,9,10,11,12 
go 
create view re_sane 
with schemabinding 
as 
    select 
     area, 
     premium_type, 
     band, 
     CASE premium_type 
      when 'fc' then 
       CASE band 
        when 12000 then fc12000 
        when 14000 then fc14000 
        when 16000 then fc16000 
       end 
      when 'sc' then 
       CASE band 
        when 12000 then sc12000 
        when 14000 then sc14000 
        when 16000 then sc16000 
       end 
     end as premium 
    from 
     dbo.re 
      cross join 
     (select 'sc' union all select 'fc') as premium_types (premium_type) 
      cross join 
     (select 12000 union all select 14000 union all select 16000) as bands (band) 
go 
select * from re_sane 

これで、re_saneビューをクエリに使用できるようになりました。カーソルを使用して動的SQLを呼び出すよりもずっと優れています。一度だけ書く必要があります。

関連する問題