Системна статистика
Преди да направите своя собствена, погледнете системната таблица pg_statistic
или изгледа pg_stats
:
Може вече да има някои от статистическите данни, които предстои да изчислите. Попълва се от ANALYZE
, така че можете да го изпълните за нови (или всякакви) таблици, преди да проверите.
-- ANALYZE tbl; -- optionally, to init / refresh
SELECT * FROM pg_stats
WHERE tablename = 'tbl'
AND schemaname = 'public';
Обща динамична plpgsql функция
Искате да върнете минималната стойност за всяка колона в дадена таблица . Това не е тривиална задача, тъй като една функция (като SQL като цяло) изисква да знае типа на връщането по време на създаване - или поне по време на извикване с помощта на полиморфни типове данни.
Тази функция прави всичко автоматично и безопасно. Работи за всеки таблица, стига агрегатната функция min()
е разрешено за всяка колона. Но вие имате нужда за да се ориентирате в PL/pgSQL.
CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
RETURNS SETOF anyelement
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
SELECT format('SELECT (t::%2$s).* FROM (SELECT min(%1$s) FROM %2$s) t'
, string_agg(quote_ident(attname), '), min(' ORDER BY attnum)
, pg_typeof(_tbl)::text)
FROM pg_attribute
WHERE attrelid = pg_typeof(_tbl)::text::regclass
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0 -- no system columns
);
END
$func$;
Обадете се (важно!):
SELECT * FROM f_min_of(NULL::tbl); -- tbl being the table name
Трябва да разберете тези понятия:
- Динамичен SQL в plpgsql с
EXECUTE
- Полиморфни типове
- Типове редове и типове таблици в Postgres
- Как да се защитим от SQL инжектиране
- Агрегирани функции
- Системни каталози
Свързан отговор с подробно обяснение:
- Името на таблицата като Параметър на функцията PostgreSQL
- Рефакторинг на PL/pgSQL функция, за да върне резултата от различни SELECT заявки
- Предаване на типа данни на Postgres
- Как да зададете стойност на полето на съставна променлива с помощта на динамичен SQL
- Как да проверя дали таблица съществува в дадена схема
- Избор на колони с определени имена на колони в PostgreSQL
- Генериране на поредица от дати - използване на тип дата като вход
Специална трудност с несъответствие на типа
Възползвам се от Postgres, дефинирайки тип ред за всяка съществуваща таблица. Използвайки концепцията за полиморфни типове, мога да създам един функция, която работи за всяка таблица.
Някои агрегатни функции обаче връщат свързани, но различни типове данни в сравнение с основната колона. Например min(varchar_column)
връща text
, което е битово съвместимо, но не точно същия тип данни. PL/pgSQL функциите имат слабо място тук и настояват за типове данни точно както е декларирано в RETURNS
клауза. Никакви опити за кастиране, дори косвени кастинги, да не говорим за кастинги на присвояване.
Това трябва да се подобри. Тествано с Postgres 9.3. Не съм тествал отново с 9.4, но съм почти сигурен, че нищо не се е променило в тази област.
Това е мястото, където тази конструкция идва като заобиколно решение :
SELECT (t::tbl).* FROM (SELECT ... FROM tbl) t;
Чрез изрично прехвърляне на целия ред към типа ред на основната таблица ние принуждаваме преобразувания на присвояване да получат оригинални типове данни за всяка колона.
Това може да се провали за някаква агрегатна функция. sum()
връща numeric
за sum(bigint_column)
за приспособяване за сума, превишаваща основния тип данни. Връщане към bigint
може да се провали...