복붙노트

[SQL] 주어진 문자열을 분할 및 사례 문을 준비

SQL

주어진 문자열을 분할 및 사례 문을 준비

테이블 : 테이블 _

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이 필요합니다 그래서.

두 개의 매개 변수를 감안할 때 :

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;

위의 업데이트 문은 작업을 수행하지만 정적으로한다.

업데이트 테이블에 같은 방식처럼 나는 매개 변수 (p_dates, p_sets)의 변화에 ​​따라 변경할 수있는 동적해야합니다 경우에만 문을 준비하려는.

질문 :

이 질문은 같은 일입니다 SQL 서버 2008 R2를 사용하여 동적 case 문에 있지만 Microsoft SQL Server에 대한 관한 것이다.

해결법

  1. ==============================

    1.클린 설치 :

    클린 설치 :

    CREATE TABLE tbl (
      given_date date
    , set_name varchar
    );
    

    단일 값에 대한 열 이름으로 단수 용어를 사용합니다. 데이터 유형은 분명히 날짜와하지 소인입니다.

    유용한 테이블에 텍스트 매개 변수를 변환하려면 :

    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;
    

    "병렬 unnest는"편리하지만주의 사항이 있습니다. 포스트 그레스 9.4 깨끗한 솔루션, 포스트 그레스 (10)이 결국이의 행동을 위생적으로 추가합니다. 아래를 참조하십시오.

    준비된 문은 만들어 세션 만 볼 수 있으며 그것으로 죽는다. 문서 별 :

    세션 당 한 번 PREPARE :

    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 :

    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) 및 () (PG 9.4) unnest 새로운 병렬.

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

    세부:

  2. ==============================

    2.String_to_array

    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;
    
  3. from https://stackoverflow.com/questions/28018991/split-given-string-and-prepare-case-statement by cc-by-sa and MIT license