Выполнить запрос, указанный текстом в ячейке таблицы

Рейтинг: 0Ответов: 1Опубликовано: 25.01.2023

Всем привет! Может кто сможет помочь с вопросом, я уже весь гугел и стэковерфлоу перерыла, может формулирую неправильно..

В общем, допустим у меня в ячейке таблицы имеется текст с запросом:

введите сюда описание изображения

При этом, неизвестно, сколько столбцов выдаст запрос и какого типа будут данные.

Возможно ли выполнить данный запрос, не используя процедурный 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";

С этим кодом вопрос решается, но насколько оптимально данное решение, можно ли составить более красивый код?

Ответы

▲ 0

можно использовать хранимые процедур и функций на языке 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;

В этом случае вам не нужно знать столбцы и типы данных, которые возвращает запрос.