Задать вопрос
Ответы пользователя по тегу PostgreSQL
  • Как хитро отпагинировать данные в PostgreSql?

    Urvin
    @Urvin Автор вопроса
    Сам спросил - сам ответил. Я нашел решение, но мне оно совсем не нравится, может, у %username% найдется чего поинтереснее.

    Проблема заключается в том, что для простейшего решения нужно иметь возможность хранить состояние, чего PostgreSql прямо не позволяет. Кажется, лучшим решением было бы написание собственной оконной функции, имеющей возможность смотреть на соседние строки, вроде lead, но интернет не изобилует примерами написания оных.

    Однако, обнаружилось, что postgres все же может позволить хранить какие-то данные, причем даже не вылезая за пределы транзакции. "Статичные переменные" можно реализовать с помощью функций current_setting / set_config. Невероятный костыль, конечно, но что есть.

    Итак, с помощью "статики" создаем функцию, которая по понятной логике щелкает страницы сортированного списка по изменению строкового ключа:
    CREATE OR REPLACE FUNCTION grouped_pagination_page(current_key VARCHAR, per_page INT4) RETURNS INT4 AS $$
      DECLARE
        last_key VARCHAR;
        last_row_count INT4;
        last_page INT4;
      BEGIN
        SELECT COALESCE(current_setting('GPP.last_key', TRUE), '') INTO last_key;
        SELECT CAST(COALESCE(NULLIF(current_setting('GPP.last_row_count', TRUE),''),'0') AS INT) INTO last_row_count;
        SELECT CAST(COALESCE(NULLIF(current_setting('GPP.last_page', TRUE),''),'1') AS INT) INTO last_page;
    
        IF current_key <> last_key THEN
          PERFORM set_config('GPP.last_key', current_key, TRUE);
          IF last_row_count >= per_page THEN
            last_page = last_page + 1;
            last_row_count = 0;
    
            PERFORM set_config('GPP.last_page', last_page::VARCHAR, TRUE);
          END IF;
        END IF;
    
        last_row_count = last_row_count + 1;
        PERFORM set_config('GPP.last_row_count', last_row_count::VARCHAR, TRUE);
    
        RETURN last_page;
      END;
    $$ LANGUAGE 'plpgsql';


    И вот, собственно, использование ее в запросе (у меня ключ группы - вендор-модель-кузов):
    SELECT *,
      MIN(price) OVER win_vendor min_price_vendor,
      MIN(price) OVER win_model min_price_model,
      MIN(price) OVER win_body min_price_body,
      grouped_pagination_page((vendor_name || model_name || body_type)::VARCHAR, 10) page_number
    FROM
      car
    WINDOW
      win_vendor AS (PARTITION BY vendor_name),
      win_model AS (PARTITION BY vendor_name, model_name),
      win_body AS (PARTITION BY vendor_name, model_name, body_type)
    ORDER BY min_price_vendor,
      min_price_model,
      min_price_body,
      price,
      specifications_name
    Ответ написан
    Комментировать
  • Как сделать группировку по двум срезам?

    Urvin
    @Urvin
    SELECT
    	fig.id,
    	SUM(vertex_cost) / COUNT(DISTINCT edge.id) vertex_sum,
    	SUM(edge_cost) / COUNT(DISTINCT vertex.id) ege_sum,
    	MIN(vertex_cost) vertex_min,
    	MIN(edge_cost) edge_min,	
    	MAX(vertex_cost) vertex_max,
    	MAX(edge_cost) edge_max		
    FROM 
    	fig
    	JOIN vertex
    		ON fig.id = vertex.fig_id
    	JOIN edge 
    		ON fig.id = edge.fig_id
    GROUP BY
    	fig.id
    Ответ написан