LINUX.ORG.RU

Аналог функции union

 


0

2

Всем привет, вопрос знатокам psql. У меня есть sql запрос, который надо выполнить к нескольким таблицам с одинаковыми столбцами, если ли возможность сделать это не через union (у меня 15 таких таблиц), а например через цикл с указанием названий таблиц? Заранее спасибо

Перемещено hobbit из general


Ответ на: комментарий от t184256

Теоретически - это могут быть запчасти от секционирования огромной таблицы, например.

И, опять же теоретически, может захотеться делать запросы по вручную заданным секциям (по 15 из 50, например) чтоб ПГ меньше думал, если мы уверены заранее, что в остальных 35 точно не может быть искомых данных.

На голом SQL мне тоже неизвестен способ.
Когда была похожая нужда - лепил строку запроса через string_agg('bla-bla',' UNION ALL '), а потом её исполнял через EXECUTE на PL/pgSQL.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

Теоретически - это могут быть запчасти от секционирования огромной таблицы, например.

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

И, опять же теоретически, может захотеться делать запросы по вручную заданным секциям (по 15 из 50, например) чтоб ПГ меньше думал

Но накладные расходы на передачу front↔DB всё равно перекроют эту экономию.

если мы уверены заранее, что в остальных 35 точно не может быть искомых данных

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

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

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

Нет, конечно. Фронтэнд вообще ничего не знает про всю эту кухню. Он запрашивает процедуру БД с параметрами. Я внутри процедуры строю строку запроса так, как считаю нужным.

Значит админ уже запросил всю таблицу

Это тоже нет. Админу не надо ничего запрашивать - он тупо наизусть знает по каким именно правилам делал секции, и в каких секциях точно не может быть данных, которые хочет фронтэнд. Оно и ПГ сам, скорее всего, хорошо попадёт в план запроса. Но, допустим, в 9.6 иногда мог промахнуться и слепить вообще все секции в плане.

Toxo2 ★★★★
()
Ответ на: комментарий от t184256

Заливаются данные из разных источников и затем берутся данные от этих самых источников, если заливать все в одну таблицу и добавлять идентификатор для каждого источника, то забирать их потом будет дольше, чем из конкретных таблиц (не надо прогонять все строки на наличие нужного идентификатора)

poprot
() автор топика
Ответ на: комментарий от poprot

По-моему - тогда как раз напрашивается одна таблица с секциями по источнику. Если в запросе будете указывать источник - ПГ сам подберет нужную. Если источника не будет - он сам их и объединит, без ручного UNION.

Toxo2 ★★★★
()
Последнее исправление: Toxo2 (всего исправлений: 1)

В любом случае все таблицы объединить в одну геморно, на каждой отдельной уже заведены проги и переписывать все намного дольше, чем написать огромный sql запрос через union. Я как раз надеялся найти способ написания sql запроса не через union, чтобы в дальнейшем к нему обращаться. Пробовал через переменные и циклы, но ничего толкового не вышло

poprot
() автор топика
Ответ на: комментарий от poprot

Ну ты не дал информации о сложности. Формально - вьюха\вьюхи на все случаи, далее адресуешь запросы к ним, вместо 100500 union. Добавить логику для materialized view по-вкусу. Костыли, но строгие, опять же от задачи все зависит.

Anoxemian ★★★★★
()
Ответ на: комментарий от Toxo2

Он запрашивает процедуру БД с параметрами. Я внутри процедуры строю строку запроса так, как считаю нужным.

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

Админу не надо ничего запрашивать - он тупо наизусть знает по каким именно правилам делал секции

Админ базы не обязательно должен быть разработчиком приложения. ☺

mord0d ★★★★★
()
Ответ на: комментарий от poprot

Раньше заливали все в одну таблицу, но из-за большой нагрузки перешли к отдельным таблицам

Это делается через partitioning: https://www.postgresql.org/docs/current/ddl-partitioning.html

После этого, тебе не надо делать запросы к отдельным таблицам, а только к родительской. Ты даже сейчас можешь поверх своих таблиц сделать родительскую через alter table ... inherits ... checks, если ты чётко знаешь по каким критериям в какую дочернюю таблицу обращаться. После этого, запросы можно будет посылать в родительскую таблицу.

AnDoR ★★★★★
()
Ответ на: комментарий от poprot

Если у тебя одинаковая структура то человечнее таки как раз запихать всё в одну таблицу и сделать партицирование по дескриминатору - типу данных. И не ломать мозг мутансткими выборками. Пусть БД работает, это её задачи.

ya-betmen ★★★★★
()
Ответ на: комментарий от mord0d

запрашивать страницы с результатами чанками в цикле

Признаться - я поплыл в этих терминах. «Страницы», «чанки» - это же из какой-то другой вселенной. Даже не совсем понимаю о чем речь.

Пример (условно-примитивно, но работоспособно)

CREATE OR REPLACE FUNCTION west_siberian_users() RETURNS TABLE(id int, nickname varchar)
LANGUAGE plpgsql
SECURITY DEFINER
AS
$f$
DECLARE 
	_v_sql varchar;
BEGIN
	SELECT string_agg('SELECT id, nickname FROM t_users_p_' || i, ' UNION ALL ')
	INTO _v_sql
	FROM UNNEST(ARRAY['tomsk', 'kemerovo', 'nsk']) i;
	RETURN QUERY EXECUTE _v_sql;
END
$f$;
и соответственно SELECT * FROM west_siberian_users(); Можно придумать условно-примитивное условие, при котором, допустим, я не захочу дать вызвавшему эту процедуру пользователю Томск, например (т.е. - не включить его в массив по которому строю UNION)

При этом эти же таблицы могут быть секциями таблицы t_users. А могут и не быть.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

Я не о возможности реализовать, я о целесообразности.

Допустим, есть сайт с 150 пользователей, на странице со списком пользователей отображается по 50, если юзер запросит вторую страницу, мы выдаём таблицу с row_id 51~100. Я не могу придумать ни одного применения циклу с row_id 1~50,51~100,101~150.

Возможно у топикстартера XY problem.

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Обычно целесообразность всё это городить появляется в районе десятков гигабайт на таблице.

сайт с 150 пользователей

а в таком случае - целесообразность использовать БД вообще сомнительна. КМК.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

сайт с 150 пользователей

а в таком случае - целесообразность использовать БД вообще сомнительна. КМК.

Ну это же просто пример. ☺ Можно 10’000’000 пользователей и по 25 пользователей на страницу во фронтэнде, сути это не поменяет.

mord0d ★★★★★
()

а что мешает генерить запрос с юнионами? есть основное тело запроса select .... from и приклеить к нему хвост, который динамически сгенерить (select ... from t1 union all select ... from tN)

правда косты таких запросов будут высокие. индексы будут очень неохотно использоваться планировщиком.

ergo ★★★
()
Последнее исправление: ergo (всего исправлений: 1)

есть.

сделать через union.

вообще, в приличном обчестве принято сразу посылать на, если условия задачи включают в себя «не делать как все это делают» без объяснения поцчему.

например через цикл с указанием названий таблиц

ты понимаешь, что такое SQL? отвечу за тебя: нет.

вопрос знатокам psql

твои мучения конкретно с постгрес никак не связаны. можно было написать знатокам SQL*Plus, ничего бы не поменялось.

anonymous
()
Ответ на: комментарий от ergo

дело в том, что тут вообще ничего генерить не надо.

если это можно сделать чистым SQL то это нужно сделать чистым SQL и не парить никому моск.

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

ну или на встройке. но в любом случае, это будет ненужным усложнением задачи (по крайней мере без доп. вводных).

anonymous
()
Ответ на: комментарий от anonymous

дурдом поста не в этом.

Ну почему же? Всегда можно представить легаси базу, где всё сделано, как сделано и другой софт работает с отдельными таблицами, а ТСу понадобилось сразу из многих таблиц получать результат. И никто не даст ему переделывать БД для одного запроса. Вот он и изобретает костыли. По идее же можно и правда собирать в цикле временную таблицу тупо select-insert, а потом отдавать результат.

Как это делается в pgsql - не знаю, но беглый гуглёж подсказывает EXECUTE.

Loki13 ★★★★★
()
Последнее исправление: Loki13 (всего исправлений: 1)