2

テーブル: table_name

create table table_name
(
given_dates timestamp,
set_name varchar
);

レコードの挿入:

insert into table_name values('2001-01-01'),('2001-01-05'),('2001-01-10'),
                 ('2001-01-15'),('2001-01-20'),('2001-01-25'),
                 ('2001-02-01'),('2001-02-05'),('2001-02-10'),
                 ('2001-02-15');

ここで、いくつかの日付の set_name を更新したいと思います。

:

次のようにテーブルを更新したい:

given_dates    set_name 
----------------------
2001-01-01      s1
2001-01-05      s1
2001-01-10      s2
2001-01-15      s2
2001-01-20
2001-01-25
2001-02-01
2001-02-05
2001-02-10
2001-02-15

:given_datesおよびset_nameは動的であるため、パラメータを渡します。上記のように 2 セット合格することs1,s2もあれば、要件に応じて 4 セット合格することもあります。

だから私は更新のための動的ケースステートメントが必要set_nameです.

2 つのパラメータが与えられた場合:

declare p_dates varchar := '2001-01-01to2001-01-05,2001-01-10to2001-01-15';

declare p_sets varchar := 's1,s2';

次の静的スクリプトを使用してこれを行うことができます。

静的更新ステートメント:

update table_name
SET set_name = 
CASE  
when given_dates between '2001-01-01' and '2001-01-05' then 's1'
when given_dates between '2001-01-10' and '2001-01-15' then 's2'
else '' 
end;

上記の update ステートメントは、ジョブを実行しますが、静的に実行します。

テーブルを更新するのと同じ方法で、パラメーターの変更に応じて変更できる動的にする必要がある case ステートメントのみを準備します(p_dates,p_sets)

質問:

  1. 指定された日付を分割する方法はp_dates? ( to2 つの日付の間にキーワードがあります。)
  2. 指定されたセットを分割する方法はp_sets? (2 つの set_names の間に「,」コンマがあります。)
  3. p_datesとを分割した後に動的な case ステートメントを準備する方法はp_sets?

この質問は、 SQL Server 2008 R2 を使用した動的ケース ステートメントに関連しています。これは、Microsoft SQL Server の場合と同じです。

4

3 に答える 3

3

クリーンセットアップ:

CREATE TABLE tbl (
  given_date date
, set_name varchar
);

単一の値の列名として単数の用語を使用します。
データ型は明らかにdateであり、 ではありませんtimestamp

テキスト パラメータを有用なテーブルに変換するには:

SELECT unnest(string_to_array('2001-01-01to2001-01-05,2001-01-10to2001-01-15', ',')) AS date_range
     , unnest(string_to_array('s1,s2', ',')) AS set_name;

「並列アンネスト」は便利ですが、注意点があります。Postgres 9.4はクリーンなソリューションを追加し、Postgres 10は最終的にこの動作をサニタイズしました。下記参照。

動的実行

作成済みステートメント

準備されたステートメントは、作成セッションにのみ表示され、それとともに終了します。ドキュメントごと:

プリペアド ステートメントは、現在のデータベース セッションの間だけ存続します。

PREPARE セッションごとに 1 回:

PREPARE upd_tbl AS
UPDATE tbl t
SET    set_name = s.set_name
FROM  (
   SELECT unnest(string_to_array($1, ',')) AS date_range
        , unnest(string_to_array($2, ',')) AS set_name
   ) s
WHERE t.given_date BETWEEN split_part(date_range, 'to', 1)::date
                       AND split_part(date_range, 'to', 2)::date;

または、クライアントが提供するツールを使用してステートメントを準備します。
任意のパラメータで n 回実行します。

EXECUTE upd_tbl('2001-01-01to2001-01-05,2001-01-10to2001-01-15', 's1,s4');

サーバー側機能

関数は永続化され、すべてのセッションに表示されます。

CREATE FUNCTION 一度

CREATE OR REPLACE FUNCTION f_upd_tbl(_date_ranges text, _names text)
  RETURNS void AS
$func$
UPDATE tbl t
SET    set_name = s.set_name
FROM  (
   SELECT unnest(string_to_array($1, ',')) AS date_range
        , unnest(string_to_array($2, ',')) AS set_name
   ) s
WHERE  t.given_date BETWEEN split_part(date_range, 'to', 1)::date
                        AND split_part(date_range, 'to', 2)::date
$func$  LANGUAGE sql;

n回呼び出す:

SELECT f_upd_tbl('2001-01-01to2001-01-05,2001-01-20to2001-01-25', 's2,s5');

SQL フィドル

優れたデザイン

配列パラメーター (引き続き文字列リテラルとして提供できます)、daterange型 (pg 9.3 の両方)、および新しい並列unnest()(pg 9.4 ) を使用します。

CREATE OR REPLACE FUNCTION f_upd_tbl(_dr daterange[], _n text[])
  RETURNS void AS
$func$
UPDATE tbl t
SET    set_name = s.set_name
FROM   unnest($1, $2) s(date_range, set_name)
WHERE  t.given_date <@ s.date_range
$func$  LANGUAGE sql;

<@「要素が含まれている」演算子です。

電話:

SELECT f_upd_tbl('{"[2001-01-01,2001-01-05]"
                  ,"[2001-01-20,2001-01-25]"}', '{s2,s5}');

詳細:

于 2015-01-29T17:09:04.283 に答える
0

String_to_array

declare p_dates varchar[] := string_to_array('2001-01-01,2001-01-05,
2001-01-10,2001-01-15*2001-01-01,2001-01-05,2001-01-10,2001-01-15','*');
declare p_sets varchar[]  := string_to_array('s1,s2',',');
declare p_length integer=0;
declare p_str  varchar[];
declare i integer;
select array_length(p_dates ,1) into p_count;

for i in 1..p_count loop

  p_str  := string_to_array( p_dates[i],',')   

  execute 'update table_name
  SET set_name = 
  CASE  
  when given_dates between'''|| p_str  [1] ||''' and '''|| p_str  [2] 
  ||''' then ''' || p_sets[1] ||'''
  when given_dates between '''|| p_str  [3] ||''' and '''
  || p_str  [4] ||''' then ''' || p_sets[2] ||'''
  else '''' 
  end';
end loop;
于 2015-01-19T07:04:41.233 に答える