Intereting Posts
Как мне группировать и заказывать с помощью sql одновременно? mysql объединяет две таблицы с разделенными запятыми идентификаторами Внутренняя таблица Join по отношению к максимальному значению Пытается использовать псевдонимы таблиц в SQL Можем ли мы иметь имя таблицы как «вариант» в MySQL? Как я могу добавить ведущие нули в даты в Oracle? Sql Server CE можно удалить TOP или только 1 запись из таблицы, которая соответствует моему запросу Команда ADO, выполняющая несколько операторов SQL: не может получить сообщение об ошибке: ИСПОЛЬЗУЙТЕ сборку Connection.Errors Правильное проектирование базы данных EAV для исторических данных Разница между тета-объединением, equijoin и естественным соединением Как создать резервную копию базы данных в файле .bak? Android проверяет, когда таблица была обновлена MySQL не вставляет обратную косую черту Ошибка запроса sql Присоединяйте таблицы SQL Server к подобному выражению

Разделить заданную строку и подготовить регистр

Таблица : имя_таблицы

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 набора в соответствии с требованием.

Поэтому мне нужен динамический оператор 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, который должен быть динамическим, который может изменяться в соответствии с параметрами (p_dates,p_sets) .

Вопросы :

  1. Как разделить заданные даты, которые являются p_dates ? (У меня есть ключевое слово между двумя датами.)
  2. Как разбить заданные множества, которые являются p_sets ? (У меня есть «,» запятая между двумя именами set_names.)
  3. Как подготовить динамический оператор case после разделения p_dates и p_sets ?

Этот вопрос относится к динамическому описанию case с использованием SQL Server 2008 R2 , что то же самое, но для Microsoft SQL Server.

    Чистая настройка:

     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; 

    «Parallel unsest» удобен, но имеет свои оговорки. Postgres 9.4 добавляет чистое решение. Смотри ниже.

    Динамическое выполнение

    Подготовленное заявление

    Подготовленные утверждения видны только для создания сеанса и умирают вместе с ним. По документации:

    Подготовленные утверждения сохраняются только в течение всего сеанса текущей базы данных.

    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 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 Fiddle

    Улучшенный дизайн

    Используйте параметры массива (все еще можно daterange как строковые литералы), тип daterange (оба pg 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;