拆分给定的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_dates和set_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)变化进行更改。 
问题 :
-  如何拆分p_dates的给定date? (我必须在两个date之间的关键字。)
-  如何拆分p_sets的给定集合? (我在两个set_name之间有','逗号。)
-  如何在分割p_dates和p_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;