Используйте результат одного запроса для запроса другого в Postgres - PullRequest
0 голосов
/ 24 ноября 2018

Я пытаюсь получить размер столбца для каждой строки в таблице.По сути, это комбинация этих двух запросов:

SELECT pg_size_pretty(sum(pg_column_size(COLUMN_NAME))) FROM TABLE_NAME;

И

SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'TABLE_NAME';

Моя первая попытка была сделать эти два запроса:

 => SELECT column_name, (SELECT pg_size_pretty(sum(pg_column_size(column_name))) FROM TABLE_NAME)  FROM information_schema.columns WHERE table_schema = 'public' AND table_name   = 'TABLE_NAME';
ERROR:  column "columns.column_name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT column_name, (SELECT pg_size_pretty(sum(pg_column_siz...
               ^
 => SELECT column_name, (SELECT pg_size_pretty(sum(pg_column_size(column_name))) FROM TABLE_NAME)  FROM information_schema.columns WHERE table_schema = 'public' AND table_name   = 'TABLE_NAME' GROUP BY column_name;
ERROR:  more than one row returned by a subquery used as an expression

Попробовал следующеетоже:

SELECT column_name, (SELECT pg_size_pretty(sum(pg_column_size(column_name))) FROM TABLE_NAME)  FROM information_schema.columns WHERE table_schema = 'public' AND table_name   = 'TABLE_NAME' GROUP BY 1;

Что вернуло:

ERROR:  more than one row returned by a subquery used as an expression

Когда я добавляю LIMIT 1, результат неверный:

SELECT column_name, 
   (SELECT pg_size_pretty(sum(pg_column_size(column_name))) FROM main_apirequest LIMIT 1)
   FROM information_schema.columns 
   WHERE table_schema = 'public' AND table_name   = 'main_apirequest'
   GROUP BY 1;

Это выглядит примерно так:

   column_name    | pg_size_pretty
------------------+----------------
 api_key_id       | 11 bytes
 id               | 3 bytes
...

Когда должно быть что-то подобное (чего не может быть из-за лимита 1)

=> SELECT pg_size_pretty(sum(pg_column_size(id))) FROM main_apirequest
;
 pg_size_pretty
----------------
 19 MB

1 Ответ

0 голосов
/ 24 ноября 2018

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

CREATE TABLE t1 (id INTEGER, txt TEXT);

INSERT INTO t1
SELECT g, random()::TEXT
FROM generate_series(1, 10) g;

Тогда SQL для генерации запроса:

DO $$
DECLARE
        query TEXT;
BEGIN
        SELECT 'SELECT ' || STRING_AGG(FORMAT('sum(pg_column_size(%1$I)) AS %1$s', column_name), ', ') || ' FROM t1'
            INTO query
        FROM information_schema.columns
        WHERE table_schema = 'public'
        AND table_name = 't1';

        RAISE NOTICE '%', query;
END $$

Созданный запрос SELECT pg_size_pretty(sum(pg_column_size(id))) AS id, pg_size_pretty(sum(pg_column_size(txt))) AS txt FROM t1

будет работать так же, еслиу вас были сотни столбцов.

Теперь, чтобы заставить его сгенерировать, выполнить запрос и вернуть вам результаты, это действительно зависит от того, что вы хотите.Если вы счастливы, просто распечатав его на экране, то, возможно, вы можете отформатировать его следующим образом:

DO $$
DECLARE
        query TEXT;
        result TEXT;
BEGIN
        SELECT 'SELECT CONCAT_WS(E''\n'', ' || STRING_AGG(FORMAT('''%1$s: '' || pg_size_pretty(sum(pg_column_size(%1$I)))', column_name), ', ') || ') FROM t1'
            INTO query
        FROM information_schema.columns
        WHERE table_schema = 'public'
        AND table_name = 't1';

        EXECUTE query
        INTO result;

        RAISE NOTICE '%', result;
END $$

Это напечатает:

id: 40 bytes
txt: 181 bytes

Если вместо этого вы хотите записьвернулся с несколькими столбцами, я не слишком уверен, как бы вы поступили, потому что количество столбцов и их имена будут неизвестны.Лучший вариант, который я могу обдумать, это вернуть его как JSON, тогда вы вернете только одну вещь, и там будет переменное число полей с любыми именами столбцов:

CREATE OR REPLACE FUNCTION test1(_schema_name TEXT, _table_name TEXT)
        RETURNS JSON AS
$$
DECLARE
        query TEXT;
        result JSON;
BEGIN
        SELECT 'SELECT ROW_TO_JSON(cols) FROM (SELECT ' || STRING_AGG(FORMAT('pg_size_pretty(sum(pg_column_size(%1$I))) AS %1$s', column_name), ', ') || ' FROM t1) AS cols'
            INTO query
        FROM information_schema.columns
        WHERE table_schema = _schema_name
        AND table_name = _table_name;

        EXECUTE query
        INTO result;

        RETURN result;
END
$$
        LANGUAGE plpgsql;

Запуск его: SELECT test1('public', 't1')

Возвращает: {"id":"40 bytes","txt":"181 bytes"}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...