PostgreSQL 8.1 CASE в строку - PullRequest
       22

PostgreSQL 8.1 CASE в строку

2 голосов
/ 24 октября 2011

У меня есть база данных, которая использует строки из 0 и 1 для представления дней в графике работы людей. Например, 0111110 будет представлять НЕТ воскресенье, ДА понедельник - пятница, НЕТ суббота. Я хотел бы извлечь это из базы данных с помощью SQL и в итоге получить строку, которая выглядит как «понедельник, вторник, среда, четверг, пятница». Это далеко, как я получил ....

   CASE 
        WHEN SUBSTR(regular_work_days, 1,1)='1' THEN 'Sunday'
        WHEN SUBSTR(regular_work_days, 2,1)='1' THEN 'Monday'
        WHEN SUBSTR(regular_work_days, 3,1)='1' THEN 'Tuesday'
        WHEN SUBSTR(regular_work_days, 4,1)='1' THEN 'Wednesday'
        WHEN SUBSTR(regular_work_days, 5,1)='1' THEN 'Thursday'
        WHEN SUBSTR(regular_work_days, 6,1)='1' THEN 'Friday'
        WHEN SUBSTR(regular_work_days, 7,1)='1' THEN 'Saturday'
        ELSE ' '
   END AS "Regular Work Days",

Как и следовало ожидать, я получаю первый «1», и никаких других дней. Я пытался добавить || но понял, что понятия не имею, как заставить это работать. Запятая не нужна, если это упрощает вещи. Помогите пожалуйста?

Ответы [ 2 ]

1 голос
/ 24 октября 2011

У вас есть только 128 возможных значений для ваших упакованных дневных строк (семь слотов и два возможных значения для каждого слота означают 128 возможностей), поэтому просто сгенерируйте таблицу, которая охватывает все опции, и присоединитесь к этой таблице, чтобы получить вашу неупакованную строку. Вы должны быть в состоянии сгенерировать такую ​​таблицу довольно легко:

packed    | unpacked
----------+-----------
'0000000' | ''
'0000001' | 'Saturday'
...
'1000001' | 'Sunday, Saturday'
...

Затем вы можете присоединить столбец упакованного дня к этой таблице на packed и выбрать unpacked, чтобы получить удобную для человека строку. Имейте в виду, что функция над конечным доменом является таблицей ассоциации, и если домен маленький, вы можете довольно легко реализовать функцию в виде таблицы.


Если вы должны сделать это трудным путем, то это будет работать в 8.1, но это довольно ужасно и должно убедить вас, что (1) вы не должны хранить свои дни таким образом и (b) вы должны справиться с этим вроде форматирования вне базы данных. Я бы не стал делать ничего подобного в реальной жизни, я включил это только потому, что хотел посмотреть, смогу ли я придумать что-нибудь, что будет работать в ограниченной среде 8.1. Возможно, вы также захотите обновить ASAP, 8.1 довольно длинный и больше не поддерживается.

Сначала вы хотите объединить таблицу названий дней:

create table days (num int not null, name varchar(9) not null);
insert into days (num, name) values (1, 'Sunday');
insert into days (num, name) values (2, 'Monday');
insert into days (num, name) values (3, 'Tuesday');
insert into days (num, name) values (4, 'Wednesday');
insert into days (num, name) values (5, 'Thursday');
insert into days (num, name) values (6, 'Friday');
insert into days (num, name) values (7, 'Saturday');

Затем пользовательский агрегат для объединения строк, разделенных запятыми:

create function comma_join(t1 text, t2 text) returns text as $$
begin
    if t1 is null or t2 is null then
        return null;
    elseif t1 = '' or t2 = '' then
        return t1 || t2;
    end if;
    return t1 || ', ' || t2;
end;
$$ language plpgsql;

create aggregate group_comma_join(
    sfunc = comma_join,
    basetype = text,
    stype = text,
    initcond = ''
);

И, наконец, функция распаковки, позволяющая скрыть все безобразия:

create function unpack_days(days_string text) returns text as $$
declare
    s text;
begin
    select group_comma_join(name)
    from (
        select name into s
        from days d join generate_series(1, 7) n(num) on d.num = n.num
        where substr(days_string, n.num, 1) = '1'
    ) dt;
    return s;
end
$$ language plpgsql;

Теперь вы можете сказать это:

=> select unpack_days('0111110');
                 unpack_days                  
----------------------------------------------
 Monday, Tuesday, Wednesday, Thursday, Friday
(1 row)

=> select unpack_days('0000000');
 unpack_days 
-------------

(1 row)
0 голосов
/ 24 октября 2011

Это должно работать.Возможно, есть более простой способ, но ...

select
    array_to_string(array_agg(
        (regexp_split_to_array('sun,mon,tue,wed,thu,fri,sat', ','))[i]
    ), ', ')
from generate_series(1, 7) i
where (regexp_split_to_array('0111110', ''))[i] = '1'

Это дает:

         daylist         
-------------------------
 mon, tue, wed, thu, fri
...