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

    Kwisatz
    @Kwisatz Автор вопроса
    Больше web-приложений, хороших и разных
    Сам спросил сам отвечу

    Все дело было в том что оператору = необходимо было указать опции restrict и join.
    Для этого надо внимательно читать не только
    https://www.postgresql.org/docs/current/sql-create...
    но так же
    https://www.postgresql.org/docs/current/xoper-opti...

    Прикладываю выдержку любезно выданную мне клодом.

    RESTRICT = eqsel
    RESTRICT — функция селективности для WHERE-условий
    Логика работы eqsel:

    Если значение есть в most_common_vals → берет частоту из most_common_freqs
    Если нет статистики → использует формулу 1 / n_distinct
    Для уникальных значений → возвращает очень малую селективность

    JOIN = eqjoinsel
    JOIN — функция селективности для JOIN-операций:
    Анализирует статистику обеих таблиц
    Оценивает количество совпадающих пар
    Учитывает кардинальность (количество уникальных значений)

    Так же приложу описание моего типа в полном объеме, возможно кому то понадобится.
    Сделал я его потому, что для выборок стали делать текстовое generated поле которое объединяло 2.5 (на самом деле поля 3, но 2 из них это id/uid) через разделитель, чтобы искать через any($param::text[]) то есть по факту, если хранить id/uid разными полями, получалось 4 поля в каждой таблице и более сложные запросы. Сделав же составной тип и описав в php для него классы типы доктрины, все стало удобней и лаконичней и в бд и в коде.

    create type entity_pointer as
    (
        type_name varchar,
        id        int,
        uid       uuid
    );
    
    ------------------------------------------------------------------------------
    -- Функция для полного сравнения
    
    create or replace function entity_pointer_cmp(entity_pointer, entity_pointer)
        returns integer as
    $$
    begin
        -- Обработка NULL значений
        if $1 is null and $2 is null then return 0; end if;
        if $1 is null then return -1; end if;
        if $2 is null then return 1; end if;
    
    -- Сравнение через ROW конструктор
        return case
                   when row (coalesce($1.type_name, ''), coalesce($1.id, 0), coalesce($1.uid, '00000000-0000-0000-0000-000000000000'::uuid)) <
                        row (coalesce($2.type_name, ''), coalesce($2.id, 0), coalesce($2.uid, '00000000-0000-0000-0000-000000000000'::uuid))
                       then -1
                   when row (coalesce($1.type_name, ''), coalesce($1.id, 0), coalesce($1.uid, '00000000-0000-0000-0000-000000000000'::uuid)) >
                        row (coalesce($2.type_name, ''), coalesce($2.id, 0), coalesce($2.uid, '00000000-0000-0000-0000-000000000000'::uuid))
                       then 1
                   else 0
            end;
    end;
    $$ language plpgsql immutable;
    
    ------------------------------------------------------------------------------
    -- хэш функция для соответствующего индекса
    
    create or replace function entity_pointer_hash(entity_pointer)
        returns integer as
    $$
    begin
        -- комбинируем значения хешей всех полей
        return coalesce(hashtext($1.type_name), 0) #
               coalesce(hashint4($1.id), 1) #
               coalesce(hashtext($1.uid::text), 2);
    end;
    $$ language plpgsql immutable
                        strict;
    
    ------------------------------------------------------------------------------
    -- Функции сравнения (нужны потому что для операторского класса функции должны возвращать bool)
    
    create or replace function entity_pointer_equal(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) = 0;
    end;
    $$ language plpgsql immutable;
    
    
    create or replace function entity_pointer_ne(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) <> 0;
    end;
    $$ language plpgsql immutable;
    
    
    -- Функции для других операторов сравнения (необходимы для B-tree)
    
    create or replace function entity_pointer_lt(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) < 0;
    end;
    $$ language plpgsql immutable;
    
    create or replace function entity_pointer_le(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) <= 0;
    end;
    $$ language plpgsql immutable;
    
    create or replace function entity_pointer_gt(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) > 0;
    end;
    $$ language plpgsql immutable;
    
    create or replace function entity_pointer_ge(entity_pointer, entity_pointer)
        returns boolean as
    $$
    begin
        return entity_pointer_cmp($1, $2) >= 0;
    end;
    $$ language plpgsql immutable;
    
    ------------------------------------------------------------------------------
    -- Создание операторов
    
    create operator = (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_equal,
        commutator = =,
        negator = <>,
        restrict = eqsel,
        join = eqjoinsel,
        hashes,
        merges
        );
    
    create operator <> (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_ne,
        commutator = <>,
        negator = =,
        restrict = neqsel,
        join = neqjoinsel
        );
    
    create operator < (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_lt,
        commutator = >,
        negator = >=,
        restrict = scalarltsel,
        join = scalarltjoinsel
        );
    
    create operator <= (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_le,
        commutator = >=,
        negator = >,
        restrict = scalarltsel,
        join = scalarltjoinsel
        );
    
    create operator > (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_gt,
        commutator = <,
        negator = <=,
        restrict = scalargtsel,
        join = scalargtjoinsel
        );
    
    create operator >= (
        leftarg = entity_pointer,
        rightarg = entity_pointer,
        function = entity_pointer_ge,
        commutator = <=,
        negator = <,
        restrict = scalargtsel,
        join = scalargtjoinsel
        );
    
    ------------------------------------------------------------------------------
    
    create operator class btree_entity_pointer_ops
        default for type entity_pointer using btree as
        operator 1 < ,
        operator 2 <= ,
        operator 3 = ,
        operator 4 >= ,
        operator 5 > ,
        function 1 entity_pointer_cmp(entity_pointer, entity_pointer);
    
    create operator class hash_entity_pointer_ops
        default for type entity_pointer using hash as
        operator 1 = ,
        function 1 entity_pointer_hash(entity_pointer);


    PS сложность средний, ага, смешная шутка...
    PSPS кстати, клод еще упоминает likesel но его я вообще в документации не нашел
    Ответ написан
    4 комментария
  • Найти сколько дней зарегистрирован пользователь?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    select extract('day' from now() - '2021-12-16 12:34:58.956416'::timestamp);
    Ответ написан
    Комментировать
  • Как сделать время для postgresql?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Записываете время выдачу (ну пусть будет created_at) и возврата(expired_at) кредита в timestamptz
    второй как alter table my_table add expired_at timestamptz generated always as ( created_at + interval '3 day');

    Затем ищете протухшие через select * where is_payed=false and expired_at
    Ну на всидку конечно)
    Ответ написан
    Комментировать
  • SELECT если есть в стоблце?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Довольно просто

    create index my_table_index_index on my_schema.my_table using gin (cast(string_to_array(index, ', ') as int[]));
    
    select *
    from my_schema.my_table 
    where string_to_array(index, ', ')::int[] @> ARRAY [1, 2, 3]::int[];
    
    select *
    from my_schema.my_table 
    where cast(string_to_array(index, ', ') as int[]) @> cast(string_to_array(:param, ', ') as int[]);


    Второй вариант запроса параметризованный и касты немного переделали чтобы не было проблем с параметрами.
    param Должен быть строкой вида '1' или '1, 2, 3';

    Кстати переделать на хранение массива можно ровно так же как тут строится индекс.
    Ответ написан
    Комментировать
  • В чем отличия оригинальной сборки Postgresql от 1Cной Postgresql?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    С оригинальной работать не будет.

    Патч пытается превратить PostgreSQL в MsSQL, например:
    Добавляет mchar, mvarchar, операторы и функции для работы с ними (модули fulleq, fasttrun, mchar)
    Добавляет 1900-01-01 в качестве дефолтного для datetime/date
    Вносит изменения в механизм блокировок и совершает еще вагон телодвижений суть которых сводится к тому чтобы 1с работала какбы с mssql
    Ответ написан
    2 комментария
  • Должен ли одинаковый запрос выполнятся с разным временем?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Конечно может, у вашей тестовой базы в кеше могут быть совершенно другие данные.
    Кстати время какое то очень большое: либо у вас с индексами проблема либо с запросом, подозреваю что второе, глядя на селект.
    Ответ написан
  • Переход на postgresql (с mysql) в миграциях laravel?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Не переживайте, как верно подметил

    Melkij
    Такие конструкторы обычно адаптированы под людей, которые не знают и знать не хотят свою базу.


    Как правило, любые нестандартные вещи из коробки поддерживаются чуть менее чем никак. Я бы даже сказал все, что выходит за грани примитивного. Более того в некоторых языках сами драйверы накладывают ограничения. Например PHP не умеет работать с PostgreSQL массивами, совсем. Как правило обходят это дело так ну или сразу используют jsonb
    Ответ написан
    1 комментарий
  • Рекурсивная загрузка дерева с вспомогательной таблицей, по ID, как?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    1. Поле id в таблице связей избыточно.
    2. Вот выбор элемента и его потомков
    with
    recursive child_elements as (
      (select id
       from links
       where id = 3)
      union
      (select lt.id
       from child_elements, links as lt
       where child_elements.id = lt.parent_id))
    select *
    from child_elements;


    3. Вот чтиво
    4. Вот доки
    Ответ написан
    2 комментария
  • Как определить значение поле по максимальному значению другого поле (PostgreSQL)?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Все зависит от ваших задач.

    Вариант номер раз

    SELECT a.stamper,
           a.city,
           AVG(a.speed) AS AVG_SPEED,
           MAX(a.speed) AS MAX_SPEED,
           (select b.station 
            from data as b 
            where b.city=a.city and
                  b.speed=max(a.speed) 
            limit 1)  as max_speed_station
    FROM  data a
    GROUP BY  a.stamper,
              a.city;


    Вариант два
    (обратите внимание, при таком типе джоина будет более одной строки после объединения если строки с подходящими скоростями в пределах города)

    select a.*,
           b.station as max_speed_station
    from (SELECT stamper,
                 city,
                 AVG(speed) AS AVG_SPEED,
                 MAX(speed) AS MAX_SPEED
          FROM data
          GROUP BY stamper,
                   city) as a
    left join data as b
      on a.city=b.city and
         a.MAX_SPEED=b.speed;
    Ответ написан
    Комментировать
  • Какие типы данных выбирать для новой базы данных для экономии места?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Я конечно извиняюсь, но таки спрошу: а зачем? объемы несерьезные.
    Ответ написан
  • Тюнинг Postgresql 10 (Postgres Pro 1C) для работы с 1С - какие параметры выставить?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Смело следуйте рекомендациям как и раньше. И унесите WAL на отдельный носитель.
    Ну и забудьте до появления каких либо тормозов/проблем.
    Ответ написан
    Комментировать
  • Postgres как сделать эффективный поиск по бд?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Смотря что ищете. Полнотекстовый поиск это одно, поиск нечетких дубликатов второе, поиск вхождения по справочникам третье, фасеточный четвертое.

    В общем случае gin индекс с pg_trgm
    Ответ написан
    Комментировать
  • Как поместить значение из поля типа BinaryField в переменную JS в template?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    В зависимости от ваших потребностей:
    select encode (my_field, 'hex') as my_bytes from my_table
    
    select encode (my_field, 'base64') as my_bytes from my_table
    Ответ написан
    Комментировать
  • Как сделать перезаписать строки в PostgreSql?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    В Postgre нет такого механизма.

    Если у вас часто возникает такая ситуация то лучше начинать с update, ибо upsert это довольно затратная штука.
    Ответ написан
    Комментировать
  • Как открыть изображение из таблицы Postgresql?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Для какой цели вы пытаетесь переложить задачи ФС на БД?
    Ответ написан
    Комментировать
  • Как сделать срез данных с базы данных, которая находится в production?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    А что не так со 100 гб дампом? Как раз есть шанс что на объеме не будет идиотских запросов.
    Ответ написан
  • Почему в услугах хостинга отсутствует PostgreSQL?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Дак купите VPS и не мучайтесь. Выходит много дешевле в итоге. Я с тех пор как в европе взял vps вообще не могу смотреть на хостинговые цены.

    А времени там нужно то, прописать dns запись, поставить Apache/ PHP/ PostgreSQL создать виртуальный хост, создать базу - все)
    Ответ написан
    Комментировать
  • Как правильно использовать pg-pool в nodejs?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Я пару лет назад пытался склепать демонстрационное приложение на ноде под мои требования: полный провал. Библиотеки для работы с pg там недоразвитые в хлам.
    По поводу пула вы можете решить это с другой стороны: pgBouncer
    Ответ написан
  • Чем может быть обусловлен отказ интегратора внедрять конфигурацию 1С с PostgreSQL в пользу MS SQL?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Исключительно баблом.
    Они еще будут вам рассказывать о сложностях настройки и поддержки. Я честно не понимаю о чем речь.
    80 гб, ну и что? Если покупаете отдельный сервак то дайте ему памяти побольше и пару ссд (под wal и сами базы)

    В общем и целом даже крупные интеграторы ведут себя неадекватно, когда разговор заходит о невиндовых решениях. Да что говорить, даже лицензию на 1с сервер посчитать нормально не могут. Посути единственный раз когда я получил полный, развернутый и исчерпывающий ответ, когда списался на хабре в личке на фоне спора в комментах к статье.
    Ответ написан
    Комментировать
  • Tsrange вывод временных интервалов?

    Kwisatz
    @Kwisatz
    Больше web-приложений, хороших и разных
    Оно?
    with
      all_ranges as (
        SELECT tsrange(generate_series, 
                       generate_series + interval '30' minute, 
                       '()') as range 
        FROM generate_series(current_date::timestamp + interval '9' hour,
                             current_date::timestamp + interval '18' hour, 
                             '30 minutes'))      
    select rooms.id as room_id,
           concat(to_char(lower(ar.range), 'HH24:MI'), 
                  ' - ', 
                  to_char(upper(ar.range), 'HH24:MI')) as timerange
    from all_ranges as ar
    cross join rooms 
    where not exists (select 1 
                      from reservations as rt
                      where rooms.id=rt.room_id and 
                            ar.range && rt.occurrence)
    order by 1;

    SQL Fiddle
    Ответ написан
    3 комментария