PLPGSQL レコードセットを列数で取得したい

このQ&Aのポイント
  • Postgresで関数(ストアドプロシージャ)を作成するのにPLPGSQLを使用しています。
  • レコードセットを取得し、1列目~40列目までを順次値を判定し、特定の値がある場合は、41列~80列のそれぞれ対応する(1列目なら41列目、13列目なら53列目…)列から数値を取得する動きを実現したいと考えています。
  • 上記条件は下記プログラムで実現してますが、再帰処理で同じことが実現できないでしょうか?
回答を見る
  • ベストアンサー

PLPGSQL レコードセットを列数で取得したい

Postgresで関数(ストアドプロシージャ)を作成するのに PLPGSQLを使用しています。 レコードセットを取得し、1列目~40列目までを順次値を判定し、特定の値がある場合は、41列~80列のそれぞれ対応する(1列目なら41列目、13列目なら53列目…)列から数値を取得する動きを実現したいと考えています。 上記条件は下記プログラムで実現してますが、再帰処理で同じことが実現できないでしょうか? ※商品マスタを作成して、クエリを作成するのが当たり前と思いますが、よんどころのない事情でこのテーブル形式をを崩せません。(外部システムの汎用データから取り込むためです) ------------------- 以下現状のプログラム ------------------- declare rec record; int1 integer; begin int1:=0; for rec in select * from kudamonouriage where syainid=$1 and kppw=$2 loop if substr(rec.kate1,1,3)='りんご' then int1:=int1+rec.kingaku1; end if; if substr(rec.kate2,1,3)='りんごthen int1:=int1+rec.kingaku2; end if; if substr(rec.kate3,1,3)='りんご' then int1:=int1+rec.kingaku3; end if; … … if substr(rec.kate39,1,3)='りんご' then int1:=int1+rec.kingaku39; end if; if substr(rec.kate40,1,3)='りんご' then int1:=int1+rec.kingaku40; end if; end loop; return int1; end; ---------------- 以上現状のプログラム --------------------- これを ------------------- 希望するプログラム ------------------- declare rec record; int1 integer; begin int1:=0; for rec in select * from kudamonouriage where syainid=$1 and kppw=$2 loop for i 1..40 loop if substr(rec.(i),1,3)='りんご' then int1:=int1+rec.(40+i); end if; end loop; end loop; return int1; end; ---------------- 以上希望のプログラム --------------------- このようにしたいと思っています。 サイト上で色々と検索していますが、解決に至っていません。お力を貸していただけると大変助かります。宜しくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.2

ANO.1です。 select kate1 kate,kingaku1 kingaku from kudamonouriage ・・・ は、 select kate1 as kate,kingaku1 as kingaku from kudamonouriage ・・・ のようにasを入れてください。 (Postgresは、asが必須だったのをうっかり。)

その他の回答 (1)

  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.1

再帰処理というか・・・。 以下で実現できるとおもうのですが・・・何かまずいことでもあるのでしょうか? for rec in select kate1 kate,kingaku1 kingaku from kudamonouriage where syainid=$1 and kppw=$2 union all select kate2 kate,kingaku2 kingaku from kudamonouriage where syainid=$1 and kppw=$2 ・・・ select kate40 kate,kingaku40 kingaku from kudamonouriage where syainid=$1 and kppw=$2 loop if substr(rec.kate,1,3)='りんご' then int1:=int1+rec.kingaku; end if; end loop; return int1; また、用語の話ですが、質問の"希望するプログラム"の方法は再帰処理とはよびません。 実行している関数自身が同じ関数を関数内で呼び出す処理のことをいいます。

mady1234
質問者

お礼

間違いのご指摘ありがとうございます。 Unionでも同様の結果は出ますね。ただ、もう少しプログラムをすっきりさせたかったため質問させていただきました。 ありがとうございました。

関連するQ&A

  • 固定長レコードの取り扱い

    ファイルから固定長のレコードを読み込んで、そのレコードから、ある項目をとりだしたいのですが・・・ レコードのフォーマット   名前 : Ch (8byte)   金額1: Int(4byte)   金額2: Int(4byte)   金額3: Int(4byte) ここから、金額2を取り出すには、どうしたら?・・・ $kingaku2 = substr($rec, 12, 4); と、やると、うまくいかない($kingaku2 の Length が 0 になってしまうような・・・)のですが・・・

    • ベストアンサー
    • Perl
  • ORA-06502のエラー

    以下のPL/SQLを実行すると、ORA-06502:数値または値のエラーとでます。途中までは、INSERTできるのですが、IF文の180個目くらいでエラーになります。そのあたりをCur1の宣言時にWhereで指定するとうまくいきます。 DECLARE CURSOR Cur1 IS SELECT MOJI FROM A_TBL ; CNT NUMBER(10); KAKKO_FL NUMBER(1); BEGIN CNT := 0; KAKKO_FL :=0; FOR Cur_Rec1 IN Cur1 LOOP FOR S IN 1 .. LENGTH(Cur_Rec1.MOJI) LOOP IF(ASCII(SUBSTR(Cur_Rec1.MOJI,S,1)) = 33129) THEN /*33129は'('*/ EXECUTE IMMEDIATE ' INSERT INTO EDD.test1116 VALUES( ''' || Cur_Rec1.MOJI || ''' ) '; END IF; END LOOP; END LOOP; END; なにがなんだか、さっぱりわからないので、どうか、ご教授ください。

  • postgres ストアドファンクションないのレコードの取得について

    質問させていただきます pg/plsqlのストアドファンクション内で 受け取った引数を sql := select * from hoge; FOR rec IN EXECUTE sql LOOP return rec.col;     <<<この部分で END LOOP; return; rec.引数名のようにして 引数から取得した 列を指定したいのですが、そのまま入れると そのような列はありませんと言うような返事を 返されてしまいます。 うまくやる方法はないものでしょうか? よろしくお願いします。

  • カーソルで集合関数を使った場合のEXCEPTION

    PL/SQLの質問です。 declare でカーソルを宣言し、その中で集合関数を使用しています。(sum) CHAR型の項目に対して掛けるので、数値でないものが入っていた場合のために INVALID ERRORのEXCEPTIONをつけました。 BEGINE  FOR rec IN cur_test  LOOP   ----  END LOOP; EXCEPTION  WHEN INVALID_NUMBER THEN   ------ END; しかし、このやりかただと、一部のレコードでエラーがあっても、 全てのレコードがエラーと判断されてしまいます。 カーソルで集合関数エラーが発生したレコードのみEXCEPTIONで扱い、 それ以外のデータはきちんとチェックしたいのですが、 そのような方法はあるでしょうか? よろしくお願いします。

  • 文字列検索後にテーブル書き出し処理

    VBにて文字列を検索し、必要な情報をテーブルの各々の項目へセットする処理を考えています。 【実際の文字列例】 AAAAA+111,BBB,CCCC+22,DDDD,EEEE,FFFF,GGGG+4444 ・・・ 文字列は1レコードが','(カンマ)で区切られ、 アルファベットが商品番号、数字がバージョンと考えて下さい。 商品番号は必ず存在しますが、バージョンは無い場合もあり、 バージョンが存在する場合は'+'(プラス)で商品番号とセットになる事を表しています。(バージョンが全く存在しない場合もあります) 既に商品番号のみをテーブルへセットする処理があり、その処理は下になります 【商品番号のみの処理】 dim pos1 dim pos2 = 1 dim itemNo LOOP pos1 := INSTR(文字列, ',', pos2); IF pos1 = 0 THEN itemNo := LTRIM(RTRIM(SUBSTR(文字列, pos2))); ELSE itemNo := LTRIM(RTRIM(SUBSTR(文字列, pos2, pos1 - pos2))); END IF; ~itemNoをテーブルへセットする処理~ END IF; EXIT WHEN pos1 = 0 pos2 = pos1 + 1 END LOOP 上記プログラムにバージョンを考慮した場合、どのように変更となるでしょうか?実プログラムをご教授くだされば幸いです。 素人の質問で申し訳ないのですが、宜しくお願い致します。

  • Do Until rs1.EOF であるレコードをスキップしたい

    ACCESS2007のVBについて教えて下さい。 テーブルをオープンし RecordSetとして、rs1、に読み込まれてきます。 あるフィールド、廃油計がゼロのときは、そのレコードに対し  処理をスキップしたいのです。 苦しまぎれに、下記のように   Continue、を使うとContinueが関数とみなされてしまいます。 ある、レコードをスキップさせたいとき、   そのようにCoding、したらいいのでしょうか? --------------------------------------- Do Until rs1.EOF If rs1![廃油計] = 0 Then continue End If ' '処理 ' rs1.MoveNext Loop ------------------------------------ よろしくお願いします。

  • 動的に生成したカラムを使ったFUNCTION

    レコード型の使用方法がわからないので、悪戦苦闘しております。。。 【やりたいこと】 ・あるテーブルのある項目でGROUP BYし、別の項目事に集計した結果を  カラムとして出力 クロス集計と呼ぶのでしょうか? 上記の結果表を取得出来るFUNCTIONを作成したいのです。 【サンプルデータ】 CREATE TABLE t1 ( col1 integer ,col2 integer ,val integer ); INSERT INTO t1 VALUES( 1, 1, 1, ); INSERT INTO t1 VALUES( 1, 1, 1, ); INSERT INTO t1 VALUES( 2, 1, 1, ); INSERT INTO t1 VALUES( 2, 1, 1, ); INSERT INTO t1 VALUES( 3, 2, 1, ); INSERT INTO t1 VALUES( 3, 2, 1, ); INSERT INTO t1 VALUES( 4, 2, 1, ); INSERT INTO t1 VALUES( 4, 2, 1, ); ※ここでcol1、col2ともどんなデータが入っているか、わからないとします。 なので、まずcol2をDISTINCTしたものを求めました。 SELECT DISTINCT col2 FROM t1; この結果をカーソルを使ってループし、動的にカラムを作成するSQLを 作りました。 DECLARE cu refcursor; rec record; str text := 'SELECT col1 '; str2 text := ' FROM t1 GROUP BY col1 ORDER BY col1'; BEGIN OPEN cu FOR EXECUTE SELECT DISTINCT col2 FROM t1; LOOP FETCH cu INTO rec; IF NOT FOUND THEN EXIT; END IF; str := str || ', SUM( CASE WHEN col2 = rec.col2 THEN val END ) AS col_name' || rec.col2; END LOOP; CLOSE cu; RAISE INFO 'key = %', str || str2;  動的に生成されたSQLを実行したい ------------------------------------------------------- ※ちなみに動的に生成されたSQLはこんな感じになります。 SELECT col1 ,SUM( CASE WHEN col2 = 1 THEN val END ) AS col_name1 ,SUM( CASE WHEN col2 = 2 THEN val END ) AS col_name2 FROM t1 GROUP BY col1 ORDER BY col1; ------------------------------------------------------- あとがわかりません。。動的なカラムなので、どうやって取得すれば 良いのでしょうか? レコード型を使うと上手くいくのでしょうか? 試しにFUNCTION( func1 )の戻り値をRETURNS SETOF record として 内部で rec1 record; : :  FOR rec1 IN EXECUTE str || str2 LOOP RETURN NEXT rec1; END LOOP; RETURN; SELECT * FROM func1(); とやってみたら、 ERROR: a column definition list is required for functions returning "record" となります。。。 カラムの定義が必要だと言われているんだと思いますが、カラムは 動的になっているので、どうすれば良いのでしょうか??

  • レコードセットからの抽出方法

    Access2000を使用しています。 下記のコードのとおり 入力用テキストボックスに座席コードを入力して seat テーブルから座席コードと入力したものからレコードを探して表示できているんですが、 レコードセットで抽出した座席番号が「P」のものだけ チェックボックス(pri.value=true) にしたいのですが動きませんどのようなコードを書けばいいんでしょうか? Dim rst As New ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "select * from seat where 座席コード='" & Me.入力用テキストボックス & "'", _ CurrentProject.Connection, adOpenKeyset, adLockOptimistic If rst.EOF = True Then MsgBox ("座席情報はありません。") Me.入力用テキストボックス = "" End If If rst.EOF = False Then Me.座席コード = rst![座席コード] Me.座席番号 = rst![座席番号] Me.入力用テキストボックス = "" Me.受付時間 = Now() End If If Left(rst![座席番号], 1) = "P" Then Me.pri.Value = True

  • MSCommについて

    ↓例の桁数、データブロックが不定で連続して受信されます。 最後の1桁は(ETX)です。 (STX)XXXXXX...(ETX)(STX)XXXXX...(FS)XXXXX...(ETX)(STX)XXXXX.......(FS)XXXX...............(ETX) すべての桁数、データブロックが対象なので一度に受信します。 1. 質問はInputプロパティで1桁ずつデータをREC変数に読み込んで、ある条件で、Loop分を抜けたいのですが、 VB6の定義方法がわかりません。 1-1.最後の(ETX)の読み込み 1-2.先頭30桁  MSComm1.InBufferCount = 0 MSComm1.InputLen = 1 Dim REC As String Do DoEvents If MSComm1.InBufferCount Then REC = REC & MSComm1.Input If ..... '最後の(ETX)の読み込み '先頭30桁 Exit Do End If   End If Loop 2. スピート重視で処理するために、InBufferCountに値があったら、すべての受信データをRECにいれたいのですが 取得できていません。 アドバイスはございますか? MSComm1.InBufferSize = 2048 MSComm1.InBufferCount = 0 MSComm1.InputLen = 0 Dim REC As String Do DoEvents If MSComm1.InBufferCount >= 1 Then Exit Do End If Loop REC = MSComm1.Input

  • アルゴリズムの実装方法

    OPEN cA; OPEN cB; <<outer_loop>> LOOP FETCH cA INTO vA; EXIT outer_loop WHEN cA%NOTFOUND; <<inner_loop>> LOOP FETCH cB INTO vB; EXIT inner_loop WHEN cB%NOTFOUND; IF vA.Pa != vB.Pb THEN --11桁で検索 vB.Pb := SUBSTR( vB.Pb, 1, 11 ); IF vB.b != vA.Pa THEN -- ログ出力 ELSE EXIT inner_loop; END IF; ELSE EXIT inner_loop; END IF; END LOOP inner_loop; 処理exec; END LOOP outer_loop; テーブルのデータはA,Bとも1件だけ作ってやっているのですが、 A.Pa = B.Pbのデータではうまく行きますが、 A.Pa != B.Pbの場合だと、処理execが行われてはいけないのに、 execが行われてしまいます。 うまく動作させるにはどういうアルゴリズムを組めばよいでしょうか? どうぞ宜しくお願いいたします。