Ответы пользователя по тегу SQL
  • Как хитро отпагинировать данные в 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
    3) Данные, по которым не производится сортировок, не шибко меняются и представляют собой какие-то законченные блоки хранить в виде Json.
    Ответ написан
    1 комментарий
  • Организация базы данных предложений и ключевых слов

    Urvin
    @Urvin
    offers
    offer_id
    offer_name

    words
    word_id
    word_name

    matching
    matching_id
    offer_id
    word_id

    SELECT
      offer_name,
      matching_count
    FROM
      (
        SELECT
          offer_id,
          offer_name,
          COUNT(*) AS matching_count
        FROM
          words
          JOIN matching USING(word_id)
          JOIN offers USING(offer_id)
        WHERE
          word_name = 'KC1'
          OR word_name = 'KC2'
        GROUP BY
          offer_id,offer_name
      ) AS mt
    ORDER BY
      matching_count DESC
    


    Если хочется очень быстро — можно сфинксом попробовать
    Ответ написан
    5 комментариев
  • Как соединить эти два запроса в один?

    Urvin
    @Urvin
    UNION?
    Ответ написан
    Комментировать