Выполнить запрос, указанный текстом в ячейке таблицы
Всем привет! Может кто сможет помочь с вопросом, я уже весь гугел и стэковерфлоу перерыла, может формулирую неправильно..
В общем, допустим у меня в ячейке таблицы имеется текст с запросом:
При этом, неизвестно, сколько столбцов выдаст запрос и какого типа будут данные.
Возможно ли выполнить данный запрос, не используя процедурный SQL?
И если невозможно, то как это сделать с помощью процедурного pl/pgsql?
Я пока смогла найти/придумать только такой способ. В процедурном не сильна :(
-- создаем функцию, которая выполняет запрос на основе переданного ей текста:
CREATE OR REPLACE FUNCTION apply_query(query TEXT)
RETURNS void AS $$
BEGIN
EXECUTE query;
END;
$$LANGUAGE plpgsql;
-- т.к. все должно выполняться автоматически, создадим еще одну функцию qr(),
-- которая результатом выдает текст нужного запроса из ячейки (код не буду приводить):
qr() => 'SELECT * FROM a'
-- создаем представление с помощью функций и запрашиваем результат:
SELECT apply_query('CREATE OR REPLACE VIEW result AS ' || qr());
SELECT * FROM "result";
С этим кодом вопрос решается, но насколько оптимально данное решение, можно ли составить более красивый код?
Ответы (1 шт):
можно использовать хранимые процедур и функций на языке PL/pgSQL.
CREATE OR REPLACE FUNCTION execute_dynamic_query(IN query_text TEXT)
RETURNS TABLE (column_name TEXT, column_value TEXT) AS $$
DECLARE
query_result RECORD;
BEGIN
EXECUTE query_text INTO query_result;
FOR i IN 0..query_result.tuple_desc.natts-1 LOOP
RETURN NEXT ROW (query_result.tuple_desc.attname[i], query_result.tuple_desc.attvalue[i]);
END LOOP;
END;
$$ LANGUAGE plpgsql;
Еще можно создать текстовый шаблон для общего SELECT запроса с плейсхолдерами для таблицы и столбцов, и затем использовать функцию форматирования строк для подстановки необходимых значений в шаблон:
-- Общий шаблон запроса
SELECT_TEMPLATE := 'SELECT * FROM %I.%I';
-- Параметры запроса
table_name := 'table_name';
column_name := 'column_name';
-- Формирование динамического запроса
EXECUTE format(SELECT_TEMPLATE, table_name, column_name);
Проблема в том, что мы не знаем, сколько столбцов и какого типа выдаст запрос, поэтому вариант с RETURNS TABLE не подходит
В данном случае можно использовать динамическое имя таблицы, чтобы сохранить результат запроса. Например, создать временную таблицу с именем, сформированным из текущей даты и времени, заполнить ее результатом запроса, и затем выбрать данные из нее.
-- создаем временную таблицу с динамическим именем
CREATE TEMP TABLE temp_table_name AS (SELECT * FROM a);
-- выбираем данные из временной таблицы
SELECT * FROM temp_table_name;
Или создать временное представление с динамическим именем
-- создаем временное представление с динамическим именем
CREATE TEMP VIEW temp_view_name AS SELECT * FROM a;
-- выбираем данные из временного представления
SELECT * FROM temp_view_name;
В этом случае вам не нужно знать столбцы и типы данных, которые возвращает запрос.
