У вас есть только 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)