2014-02-07 14 views
1

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

select sum(user_count) as user_count_sum, sum(min_count) as min_count_sum, 
sum(max_count) as max_count_sum 
from(
select max(case when di = 'i' then di_count end) as user_count, 
     min(di_count) as min_count, 
     max(di_count) as max_count 
from (
    select di, 
      count(distinct rt) as di_count 
    from gpstablev2 
    where rt > GETDATE() - '1 day'::INTERVAL 
    group by di 
) 
UNION 
select max(case when di = 'i' then di_count end) as user_count, 
     min(di_count) as min_count, 
     max(di_count) as max_count 
from (
    select di, 
      count(distinct rt) as di_count 
    from powertablev2 
    where rt > GETDATE() - '1 day'::INTERVAL 
    group by di 
) 
) 

Теперь у меня есть мастер-таблицу, что если бы я, чтобы запустить следующий запрос будет возвращен следующий

select table from mastertable; 

gpstablev2 
powertablev2 
...(more table names) 

Вместо того, чтобы вставить еще 9 UNION блоков, как тот, который я должен суммировать все таблицы, перечисленные в mastertable, есть способ, которым я могу использовать запрос для mastertable, чтобы очистить это?

Если бы я делал это в java, я бы сначала получил свой ResultSet из главной таблицы, а затем сам выполнил 10 запросов и UNION. Но я предпочитаю, чтобы моя база данных выполняла ВСЕ обработку и могла обновляться на основе содержимого mastertable.

EDIT: На основе обратной связи я пытаюсь динамический запрос и получил это далеко, но я до сих пор имеют проблемы воедино остальные куски

CREATE OR REPLACE FUNCTION get_sums() 
RETURNS TABLE(user_count_sum bigint, min_count_sum bigint, max_count_sum bigint) 
$BODY$ 
BEGIN 

RETURN QUERY EXECUTE " 
SELECT $$SELECT sum(user_count) AS user_count_sum 
     ,sum(min_count) AS min_count_sum 
     ,sum(max_count) AS max_count_sum 
FROM (
    SELECT max(case when di = 'id' then di_count end) AS user_count 
     ,min(di_count) AS min_count 
     ,max(di_count) AS max_count 
    FROM ($$ 
|| 
string_agg(format($$ 
     (SELECT di, count(distinct rt) AS di_count 
     FROM %I 
     WHERE rt > now() - interval '1 day' 
     GROUP BY 1)$$, tbl) 
     ,' 

     UNION ALL') 
|| ' 
    ) sub1 
    ) sub2' 
FROM mastertable; 
INTO results_var" 

END; 
$BODY$ 
LANGUAGE plpqsql; 
+0

Вы можете сделать это с помощью динамического SQL (google для 'EXECUTE') внутри функции PL/pgSQL. –

+0

Я вижу, просто ищет немного больше, как выполнить Dynamic SQL. Попытка узнать из этого примера http://stackoverflow.com/questions/12028041/select-a-dynamic-set-of-columns-from-a-table-and-get-the-sum-for-each/12031145 # 12031145 –

+1

Определения типов отсутствуют. Должно быть: 'RETURNS TABLE (user_count_sum bigint, min_count_sum bigint, max_count_sum bigint)'. Остальное выглядит хорошо сейчас, быстро взглянув на него. –

ответ

0

Вам необходимы динамического SQL для этого. SQL не принимает динамическое преобразование литералов/значений в идентификаторы. Поэтому вам нужно сначала создать запрос, а затем выполнить его. Вы можете сделать это в вашем клиенте (кажется, Java), или сделать это все внутри Postgres, которая, как правило, быстро:

SELECT $$SELECT sum(user_count) AS user_count_sum 
     ,sum(min_count) AS min_count_sum 
     ,sum(max_count) AS max_count_sum 
FROM (
    ($$ 
|| 
string_agg(format($$ 
    SELECT max(case when di = 'i' then di_count end) AS user_count 
     ,min(di_count) AS min_count 
     ,max(di_count) AS max_count 
    FROM (
     SELECT di, count(distinct rt) AS di_count 
     FROM %I 
     WHERE rt > now() - interval '1 day' 
     GROUP BY 1 
    ) t 
    )$$, tbl) 
     ,' 

    UNION ALL 
    (') 
|| ' 
    ) sub' 
FROM mastertable; 

Производит строки запроса:

SELECT sum(user_count) AS user_count_sum 
     ,sum(min_count) AS min_count_sum 
     ,sum(max_count) AS max_count_sum 
FROM (
    (
    SELECT max(case when di = 'i' then di_count end) AS user_count 
     ,min(di_count) AS min_count 
     ,max(di_count) AS max_count 
    FROM (
     SELECT di, count(distinct rt) AS di_count 
     FROM gpstablev2 
     WHERE rt > now() - interval '1 day' 
     GROUP BY 1 
    ) t 
    ) 

    UNION ALL 
    (
    SELECT max(case when di = 'i' then di_count end) AS user_count 
     ,min(di_count) AS min_count 
     ,max(di_count) AS max_count 
    FROM (
     SELECT di, count(distinct rt) AS di_count 
     FROM powertablev2 
     WHERE rt > now() - interval '1 day' 
     GROUP BY 1 
    ) t 
    ) 

    UNION ALL 
    ... 

    ) sub; 
  • GETDATE() недействительна функция Postgres. Вероятно, вы имеете в виду now() или CURRENT_DATE .. в зависимости от нераскрытого типа rt. Вместо этого я использую now().

  • Вы, скорее всего, нужно использовать UNION ALL вместо UNION здесь.

  • Также исправлены отсутствующие псевдонимы для подзапросов и сделаны некоторые незначительные упрощения.

Оберните это в plpgsql функции с EXECUTE. Есть plenty of closely related examples here on SO с кодом и ссылками и объяснением ...

+1

Ваш запрос отличается от запроса. Вам нужно переместить агрегаты max/min в каждый подзапрос. –

+0

@IgorRomanchenko: Верно, спасибо. Один уровень запроса был искажен. –

Смежные вопросы