拆分给定的string,并准备case语句

:table_name

create table table_name ( given_dates timestamp, set_name varchar ); 

插入logging

 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'); 

现在我想更新一些date的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_datesset_name是传递参数,因为它们是dynamic的。 我可以按照上面s1,s2通过2台s1,s2也可以按要求通过4台。

所以我需要dynamic的case语句来更新set_name

给定两个参数

 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; 

上面的更新语句完成了工作,但静态地完成了。

就像更新表的方法一样,我只想准备case语句,它应该是dynamic的,可以根据参数(p_dates,p_sets)变化进行更改。

问题

  1. 如何拆分p_dates的给定date? (我必须在两个date之间的关键字。)
  2. 如何拆分p_sets的给定集合? (我在两个set_name之间有','逗号。)
  3. 如何在分割p_datesp_sets之后准备dynamiccase语句?

这个问题涉及使用SQL Server 2008 R2的Dynamic case语句 ,这与Microsoft SQL Server是一样的。

清洁设置:

 CREATE TABLE tbl ( given_date date , set_name varchar ); 

使用单个词作为单个值的列名称。
数据types显然是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增加了一个干净的解决scheme。 见下文。

dynamic执行

准备好的声明

准备好的陈述仅在创build会话中可见,并随之死亡。 每个文档:

准备的语句仅在当前数据库会话期间持续。

每次会议准备一次

 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'); 

服务器端function

function是持久的,并可见所有会话。

一次 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小提琴

卓越的devise

使用数组参数(仍然可以作为string文字提供), daterangetypes(两个页面9.3)和新的并行unnest() (第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}'); 

细节:

  • 最平行的多个数组

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;