#sql #postgresql #plpgsql
Вопрос:
Проблема
(Это для библиотеки аналитики с открытым исходным кодом.)
Вот результаты нашего запроса от events_view
:
id | visit_id | name | prop0 | prop1 | url
------ ---------- -------- ---------------------------- ------- ------------
2004 | 4 | Magnus | 2021-10-26 02:25:55.790999 | 142 | cnn.com
2007 | 4 | Hartis | 2021-10-26 02:26:37.773999 | 25 | fox.com
В настоящее время все столбцы находятся VARCHAR
.
Column | Type | Collation | Nullable | Default
---------- ------------------- ----------- ---------- ---------
id | bigint | | |
visit_id | character varying | | |
name | character varying | | |
prop0 | character varying | | |
prop1 | character varying | | |
url | character varying | | |
Они должны быть чем-то вроде
Column | Type | Collation | Nullable | Default
---------- ------------------------ ----------- ---------- ---------
id | bigint | | |
visit_id | bigint | | |
name | character varying | | |
prop0 | time without time zone | | |
prop1 | bigint | | |
url | character varying | | |
Желаемый результат
Жесткое кодирование этих приведений, как в SELECT visit::bigint, name::varchar, prop0::time, prop1::integer, url::varchar FROM tbl
, не подходит, имена столбцов известны только во время выполнения.
Для упрощения мы могли бы разбить каждый столбец только на три типа: логический, числовой или переменный. Используйте регулярные выражения ниже для сопоставления типов:
- логический:
^(true|false|t|f)$
- числовой:
^(,-)[0-9] (,.[0-9] )$
- varchar: каждый результат, который не соответствует логическому и числовому выше
Каким должен быть SQL, который определяет, к какому типу относится каждый столбец, и динамически приводит их?
Комментарии:
1. Не связано: вы действительно используете PostgreSQL 9.4? Он достиг ЭОЛА давным-давно.
2. Что делать, если столбец содержит несколько различных обнаруженных типов данных?
3. @jarlh мы сопоставим регулярное выражение для идентификации, чтобы упростить использование первого ненулевого значения столбца.
Ответ №1:
Это несколько идей, а не истинное решение для этой сложной работы. Вместо регулярных выражений можно использовать медленную, но очень надежную функцию.
create or replace function can_cast(s text, vtype text)
returns boolean language plpgsql immutable as
$body$
begin
execute format('select %L::%s', s, vtype);
return true;
exception when others then
return false;
end;
$body$;
Данные могут быть представлены следующим образом (частичный список столбцов из вашего примера):
create or replace temporary view tv(id, visit_id, prop0, prop1) as
values
(
2004::bigint,
4::bigint,
case when can_cast('2021-10-26 02:25:55.790999', 'time') then '2021-10-26 02:25:55.790999'::time end,
case when can_cast('142', 'bigint') then '142'::bigint end
), -- determine the types
(2007, 4, '2021-10-26 02:26:37.773999', 25)
-- the rest of the data here;
Я считаю, что также возможно динамически генерировать DDL временного представления как select
от events_view
.
Комментарии:
1. Хорошее понимание, я нашел решение для своей проблемы, создав для каждого атрибута/столбца таблицу с типами кандидатов, а затем выбрав те, которые имеют наиболее допустимые значения. Довольно сложно и медленно, но работает.