SQLを使用してPostgres db 8.1のすべてのシーケンスを一覧表示する


147

私はdbをpostgresからmysqlに変換しています。

トリック自体を実行するツールが見つからないため、mysqlですべてのpostgresシーケンスをautoincrement値を持つautoincrement idに変換します。

では、Postgres DB(8.1バージョン)のすべてのシーケンスを、それが使用されているテーブル、次の値などの情報とともにSQLクエリで一覧表示するにはどうすればよいですか?

information_schema.sequences8.4リリースではビューを使用できないことに注意してください。


1
変換が間違った方法で行われていることに注意してください。OracleはSunを買収して以来、MySQLを徐々に殺し続けているため、クライアントを軽蔑しない限り(この場合は単に終了する必要があります)PostgreSQLに固執する必要があります。最終的には独自のデータベースに置き換えます。
John

@ジョン私はpostgresに固執する理由が10億と他に1つあり、mysqlに触れないためには10億以上の理由があると思いますが、はい-あなたのポイントはまだ非常に有効です:)
Ruslan

@ジョン(当時)(2009)には、より簡単なデータベースを処理する必要があります
-mysqlは

回答:


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自動作成シーケンスの場合
Evgeny Nozdrev 2018

80

PostgreSQL 8.4以降では、データベースで使用されるシーケンスに関するすべての情報を次の方法で取得できることに注意してください。

SELECT * FROM information_schema.sequences;

私はPostgreSQLのより高いバージョン(9.1)を使用していて、同じ答えを高くも低くも探していたので、後世のために、そして将来の検索者のためにこの答えを追加しました。


1
Protip:回答を「アクティブ」で並べ替えます。質問はますます古いなってきているよう後世に...より多くの関連を取得
raveren

1
涼しい。そして、「アクティブ」なソート方法を選択した場合、サイトは設定をすぐに記憶しているように見えます(ここでは、デフォルトとして設定する場所を探して、利用できないように設定を探していました)。ええと、もし私たちが「質問者が受け入れた答えが自動的に他のすべてに勝つわけではない」という選択肢さえあれば、それは後世にとって本当に素晴らしい勝利でしょう。
SeldomNeedy 2015

このテーブルはPG 8.4で導入されたことに注意してください。公式ドキュメントの後にPG 8.2と言いたいのですが
。postgresql.org/docs

その「すべての情報」には、現在の値は含まれていません。
バート

62

:実行しpsql -Eた後、および\ds


1
シーケンスのリストだけでなく、それが使用されているテーブル、次の値なども必要です。SQLでそれを行う必要があります
apelliciari

次に、すべてのシーケンスで\ d <name>を実行します(まだpsql -Eのままです)

繰り返しますが、これはSQLにはなく、シーケンスがアタッチされているテーブルは表示されません
apelliciari

@avastreg:私が言ったとおりに実行しましたか?そしてなぜそうではないのですか?

10
@avastreg:JUST DO IT ONCE。そしてそれはあなたにクエリを表示します!

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列用に作成されたシーケンスなど)と親テーブルの関係は、シーケンス所有者属性によってモデル化されます。

この関係は、ALTER SEQUENCEコマンドの OWNED BY句を使用して変更できます。

例:foo_schema.foo_tableによってALTER SEQUENCE foo_id OWNED

テーブルfoo_tableにリンクするように設定する

またはALTER SEQUENCE foo_id OWNED by NONE

シーケンスとテーブルの間の接続を切断する

この関係に関する情報は、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' ;

テーブルとシーケンス間の依存関係の有用な説明。ただし、クエリですべてのシーケンスが検出されたわけではありません。一部のシーケンスは依存関係なしに存在しているようです。
Evgeny Nozdrev 2018

はい、このクエリは、データベースのシリアル列定義で定義されたシーケンスのみを明示的に示しています。これは答えで説明されています。
cms

5

私はこの投稿がかなり古いことを知っていますが、シーケンスをテーブルと列にリンクする自動化された方法を探していて共有したかったので、CMSによるソリューションが非常に役立つことがわかりました。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
説明なしでコードを記述しないでください。また、あなたのコードは「以前の答えの改善」であると述べたので、それが改善である理由も教えてください。ああ、あきらめないで、SOへようこそ!
Joel

正確なコード(行の組み合わせ)ではなく、意味のないテキストのページを作成する必要がありますか?
Alexander Ryabov 14

2
そんなことは言わなかった。シンプルで正確なコードが好きです。ただし、コードが改善されたと述べる場合、改善の理由を1行または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;

クレジットが支払われるべきクレジット...それは、シーケンスがあった既知のテーブルの\ dからログに記録されたSQLから部分的にリバースエンジニアリングされます。きっともっときれいになると思いますが、ちょっと、パフォーマンスは気になりませんでした。


1

ハックの一種ですが、これを試してください:

「選択」を選択する」|| relname || シーケンスとしての '' '、' ||のlast_value relname || 'union' FROM pg_catalog.pg_class c WHERE 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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.