Список всех последовательностей в Postgres DB 8.1 с SQL


147

Я конвертирую БД из Postgres в MySQL.

Так как я не могу найти инструмент, который делает сам трюк, я собираюсь преобразовать все последовательности postgres в идентификаторы автоинкремента в mysql со значением автоинкремента.

Итак, как мне перечислить все последовательности в базе данных Postgres ( версия 8.1 ) с информацией о таблице, в которой она используется, следующем значении и т. Д. С запросом SQL?

Имейте в information_schema.sequencesвиду, что я не могу использовать представление в версии 8.4.


1
Следует отметить, что вы делаете конвертацию неправильно. С тех пор, как Oracle купила Sun, они постепенно убивают MySQL, поэтому, если вы не презираете своего клиента (в этом случае вам следует просто выйти), вам следует придерживаться PostgreSQL, поскольку ни одна корпорация (pro-monopoly of not) не может прийти, поглотить PostgreSQL и в конце концов замените его собственной базой данных.
Джон

@ Джон, я бы сказал, что есть миллиард и еще одна причина, чтобы придерживаться postgres, и еще миллиард, чтобы никогда не трогать mysql, но да - ваша точка зрения остается в силе :)
Руслан

@John в то время (2009) нам нужна более простая база данных для работы - и mysql был лучше связан с php
apelliciari

Ответы:


251

Следующий запрос дает имена всех последовательностей.

SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';

Обычно последовательность называется как ${table}_id_seq. Простое сопоставление с регулярным выражением даст вам имя таблицы.

Чтобы получить последнее значение последовательности, используйте следующий запрос:

SELECT last_value FROM test_id_seq;

5
${table}_id_seqНамек был полезен
Пьер де LESPINAY

${table}_${column}_seqдля автоматически созданных последовательностей
Евгений Ноздрев

81

Обратите внимание, что начиная с PostgreSQL 8.4 вы можете получить всю информацию о последовательностях, используемых в базе данных:

SELECT * FROM information_schema.sequences;

Поскольку я использую более высокую версию PostgreSQL (9.1) и искал один и тот же ответ, высокий и низкий, я добавил этот ответ для будущих поколений и для будущих пользователей.


1
Подсказка: сортируйте ответы по «активным». Потомство становится все более актуальным, так как вопросы становятся все более старыми ..
Раверен

1
Прохладно. И похоже, что если я выберу «активный» метод сортировки, сайт сразу запоминает настройки (здесь я копался в настройках, чтобы найти место для установки по умолчанию, но безрезультатно). Хм, теперь, если бы только у нас был вариант «ответ, принятый спрашивающим, автоматически не превосходит все остальное», это было бы поистине великой победой для потомков.
SeldomNeedy

Обратите внимание, что эта таблица была введена в PG 8.4, я бы скорее сказал, PG 8.2 после официальной документации: postgresql.org/docs/8.2/infoschema-septions.html
Гийом

Эта «вся информация» не включает текущее значение.
Барт

62

Запустите:, psql -Eа затем\ds


1
мне не нужен только список последовательностей, мне нужна таблица, в которой он используется, следующее значение и т. д. И я должен сделать это в SQL
apelliciari

Затем в каждой последовательности выполните \ d <имя> (все еще в psql -E)

опять же, это не в SQL и не показывает, к какой таблице присоединена последовательность
apelliciari

@avastreg: ты сделал так, как я тебе сказал? и почему бы нет?

10
@avastreg: просто сделай это раз . И он покажет вам запросы!

26

после небольшой боли я понял.

лучший способ добиться этого - перечислить все таблицы

select * from pg_tables where schemaname = '<schema_name>'

а затем, для каждой таблицы, перечислите все столбцы с атрибутами

select * from information_schema.columns where table_name = '<table_name>'

затем для каждого столбца проверьте, имеет ли он последовательность

select pg_get_serial_sequence('<table_name>', '<column_name>')

а затем получить информацию об этой последовательности

select * from <sequence_name>

13

информация о последовательности: максимальное значение

SELECT * FROM information_schema.sequences;

информация о последовательности: последнее значение

SELECT * FROM <sequence_name>


11

Связь между автоматически сгенерированными последовательностями (например, созданными для столбцов SERIAL) и родительской таблицей моделируется атрибутом владельца последовательности.

Вы можете изменить это отношение, используя предложение OWNED BY команды ALTER SEQUENCE.

например, ALTER SEQUENCE foo_id, СОБСТВЕННЫЙ от foo_schema.foo_table

установить привязку к таблице foo_table

или ПОСЛЕДОВАТЕЛЬНАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ foo_id, СОБСТВЕННАЯ ОТСУТСТВУЕТ

разорвать связь между последовательностью и любой таблицей

Информация об этом отношении хранится в таблице каталога pg_depend .

отношение соединения - это связь между pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - которая связывает последовательность с записью соединения, а затем pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', которая связывает присоединить запись к собственному отношению (таблица)

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

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname , 
                           c.relkind, c.relname AS relation 
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),  
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )  
SELECT
       s.fqname AS sequence, 
       '->' as depends, 
       t.fqname AS table 
FROM 
     pg_depend d JOIN sequences s ON s.oid = d.objid  
                 JOIN tables t ON t.oid = d.refobjid  
WHERE 
     d.deptype = 'a' ;

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

да, этот запрос явно демонстрирует только последовательности, которые определены в определениях последовательных столбцов базы данных. Это объясняется в ответе.
cms

5

Я знаю, что этот пост довольно старый, но я нашел решение CMS очень полезным, так как я искал автоматический способ связать последовательность со столбцом таблицы AND и хотел поделиться им. Использование таблицы каталога pg_depend было ключевым. Я расширил то, что было сделано, чтобы:

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,
                           c.relkind, c.relname AS relation
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       '->' as depends,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' ;

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

CREATE OR REPLACE FUNCTION public.reset_sequence(tablename text, columnname text)
 RETURNS void
 LANGUAGE plpgsql
AS $function$
DECLARE
    _sql VARCHAR := '';
BEGIN
    _sql := $$SELECT setval( pg_get_serial_sequence('$$ || tablename || $$', '$$ || columnname || $$'), (SELECT COALESCE(MAX($$ || columnname || $$),1) FROM $$ || tablename || $$), true)$$;
    EXECUTE _sql;
END;
$function$;

Надеюсь, это поможет кому-то сбросить последовательности!


Через несколько лет я замечаю ваше обновление и захожу, чтобы высказать свое мнение :-)
cms

3

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

Код:

    SELECT t.relname as related_table, 
           a.attname as related_column,
           s.relname as sequence_name
    FROM pg_class s 
      JOIN pg_depend d ON d.objid = s.oid 
      JOIN pg_class t ON d.objid = s.oid AND d.refobjid = t.oid 
      JOIN pg_attribute a ON (d.refobjid, d.refobjsubid) = (a.attrelid, a.attnum)
      JOIN pg_namespace n ON n.oid = s.relnamespace 
    WHERE s.relkind     = 'S' 

  AND n.nspname     = 'public'

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


2

Улучшение предыдущего ответа:

select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname) 
from pg_class where relkind ='S'

3
Пожалуйста, не помещайте свой код без объяснения причин. Кроме того, поскольку вы заявили, что ваш код является «улучшением предыдущего ответа», вы также должны сообщить нам, ПОЧЕМУ это улучшение. О, не сдавайся, и добро пожаловать на ТАК!
Джоэл

Должен ли я написать страницу бессмысленного текста вместо точного кода (пара строк)?
Александр Рябов

2
Никогда этого не говорил. Мне нравится простой, точный код. Но если заявить, что ваш код является улучшением, одна или две строки, объясняющие ПОЧЕМУ это улучшение (лучшая читаемость, улучшенная производительность и т. Д.), Не повредят. И вы, вероятно, тоже получите +1 от меня.
Джоэл

1

Частично проверено, но выглядит в основном завершенным.

select *
  from (select n.nspname,c.relname,
               (select substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                  from pg_catalog.pg_attrdef d
                 where d.adrelid=a.attrelid
                   and d.adnum=a.attnum
                   and a.atthasdef) as def
          from pg_class c, pg_attribute a, pg_namespace n
         where c.relkind='r'
           and c.oid=a.attrelid
           and n.oid=c.relnamespace
           and a.atthasdef
           and a.atttypid=20) x
 where x.def ~ '^nextval'
 order by nspname,relname;

Кредит, при котором кредит должен быть ... он частично обратно спроектирован из SQL, записанного из \ d в известной таблице с последовательностью. Я уверен, что это тоже может быть чище, но эй, производительность не была проблемой.


1

Что-то вроде хака, но попробуйте это:

выберите «выбрать» || relname || '' 'как последовательность, last_value из' || relname || 'union' FROM pg_catalog.pg_class c ГДЕ c.relkind IN ('S', '');

Удалить последний UNION и выполнить результат


1

Получите последовательности по каждому столбцу каждой таблицы с помощью синтаксического анализа предложения DEFAULT. Этот метод предоставляет информацию о том, с какими последовательностями столбцов связаны, и не использует зависимости, которые могут не существовать для некоторых последовательностей. Даже pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)функция нашла не все последовательности для меня!

Решение:

SELECT
    seq_sch.nspname  AS sequence_schema
  , seq.relname      AS sequence_name
  , seq_use."schema" AS used_in_schema
  , seq_use."table"  AS used_in_table
  , seq_use."column" AS used_in_column
FROM pg_class seq
  INNER JOIN pg_namespace seq_sch ON seq_sch.oid = seq.relnamespace
  LEFT JOIN (
              SELECT
                  sch.nspname AS "schema"
                , tbl.relname AS "table"
                , col.attname AS "column"
                , regexp_split_to_array(
                      TRIM(LEADING 'nextval(''' FROM
                           TRIM(TRAILING '''::regclass)' FROM
                                pg_get_expr(def.adbin, tbl.oid, TRUE)
                           )
                      )
                      , '\.'
                  )           AS column_sequence
              FROM pg_class tbl --the table
                INNER JOIN pg_namespace sch ON sch.oid = tbl.relnamespace
                --schema
                INNER JOIN pg_attribute col ON col.attrelid = tbl.oid
                --columns
                INNER JOIN pg_attrdef def ON (def.adrelid = tbl.oid AND def.adnum = col.attnum) --default values for columns
              WHERE tbl.relkind = 'r' --regular relations (tables) only
                    AND col.attnum > 0 --regular columns only
                    AND def.adsrc LIKE 'nextval(%)' --sequences only
            ) seq_use ON (seq_use.column_sequence [1] = seq_sch.nspname AND seq_use.column_sequence [2] = seq.relname)
WHERE seq.relkind = 'S' --sequences only
ORDER BY sequence_schema, sequence_name;

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


0

Спасибо за вашу помощь.

Вот функция pl / pgsql, которая обновляет каждую последовательность базы данных.

---------------------------------------------------------------------------------------------------------
--- Nom : reset_sequence
--- Description : Générique - met à jour les séquences au max de l'identifiant
---------------------------------------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION reset_sequence() RETURNS void AS 
$BODY$
DECLARE _sql VARCHAR := '';
DECLARE result threecol%rowtype; 
BEGIN
FOR result IN 
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,c.relkind, c.relname AS relation FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
    sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
    tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' 
LOOP
     EXECUTE 'SELECT setval('''||result.col1||''', COALESCE((SELECT MAX('||result.col3||')+1 FROM '||result.col2||'), 1), false);';
END LOOP;
END;$BODY$ LANGUAGE plpgsql;

SELECT * FROM reset_sequence();

0

Вот еще один, который имеет имя схемы рядом с именем последовательности

select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = 'S' order by nspname

0

Эта функция показывает last_value каждой последовательности.

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

drop function if exists public.show_sequence_stats();
CREATE OR REPLACE FUNCTION public.show_sequence_stats()
    RETURNS TABLE(tablename text, last_value bigint) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
    ROWS 1000
AS $BODY$
declare r refcursor; rec record; dynamic_query varchar;
        BEGIN
            dynamic_query='select tablename,last_value from (';
            open r for execute 'select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = ''S'' order by nspname'; 
            fetch next from r into rec;
            while found 
            loop
                dynamic_query=dynamic_query || 'select '''|| rec.nspname || '.' || rec.relname ||''' "tablename",last_value from ' || rec.nspname || '.' || rec.relname || ' union all ';
                fetch next from r into rec; 
            end loop;
            close r; 
            dynamic_query=rtrim(dynamic_query,'union all') || ') x order by last_value desc;';
            return query execute dynamic_query;
        END;
$BODY$;

select * from show_sequence_stats();

0

Предполагая, что exec()функция объявлена ​​в этом посте https://stackoverflow.com/a/46721603/653539 , последовательности вместе с их последними значениями могут быть получены с помощью одного запроса:

select s.sequence_schema, s.sequence_name,
  (select * from exec('select last_value from ' || s.sequence_schema || '.' || s.sequence_name) as e(lv bigint)) last_value
from information_schema.sequences s

0
select sequence_name, (xpath('/row/last_value/text()', xml_count))[1]::text::int as last_value
from (
    select sequence_schema,
            sequence_name,         
            query_to_xml(format('select last_value from %I.%I', sequence_schema, sequence_name), false, true, '') as xml_count
    from information_schema.sequences
    where sequence_schema = 'public'
) new_table order by last_value desc;

0

Вот пример того, как использовать, psqlчтобы получить список всех последовательностей с их last_value:

psql -U <username> -d <database> -t -c "SELECT 'SELECT ''' || c.relname || ''' as sequence_name, last_value FROM ' || c.relname || ';' FROM pg_class c WHERE (c.relkind = 'S')" | psql -U <username> -d <database> -t

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.