拆分给定的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文字提供), daterange
types(两个页面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;