web-dev-qa-db-ja.com

PostgreSQLの主キーがテストテーブルから消える

作成したテストテーブルwith主キーが主キーを返さないというやや複雑なシナリオがあります。 pgAdmin IIIは、制約がないと報告しています。 PostgreSQLクエリログ全体があり、以下にテストテーブルの作成に使用したクエリがあります。次に、主キーを別のテストテーブルにドロップし、生成されたクエリ(手動で実行したクエリではありません)を使用して、pgAdmin IIIを検索し、問題のテーブルに主キーをドロップしましたが、何も検索されませんでした。

ALTER TABLE public.delete_key_bigserial DROP CONSTRAINT

文字列「DROPCONSTRAINT」は、テストテーブルを作成する数週間前の2014-12-02にさかのぼるクエリログに1回だけ表示されます。主キーがbigserialまたはserialに設定されている場合とされていない場合があり、主キーのIDを整数に設定してからidを設定せずにテーブルを作成したこともわかりました。主キーになります(全日のワームの別の缶)。

以前の質問data_typeを取得する方法について質問しました。これには、ErwinBrandstetterが優れた回答をしたbigserialまたはserialのどちらであるかが含まれます。彼は特に2つのクエリを提供しました。1つはすべての列のdata_typesをフェッチし、もう1つは主キーのdata_typeをフェッチします。残念ながら、私がテストしてきたテストテーブルの1つは、結果を返していません。

SELECT a.attrelid::regclass::text, a.attname,
CASE a.atttypid
 WHEN 'int'::regtype  THEN 'serial'
 WHEN 'int8'::regtype THEN 'bigserial'
 WHEN 'int2'::regtype THEN 'smallserial'
 END AS serial_type
FROM   pg_attribute  a
JOIN   pg_constraint c ON c.conrelid  = a.attrelid AND c.conkey[1] = a.attnum 
JOIN   pg_attrdef   ad ON ad.adrelid  = a.attrelid
                       AND ad.adnum   = a.attnum
WHERE  a.attrelid = 'delete_key_bigserial'::regclass
AND    a.attnum > 0
AND    NOT a.attisdropped
AND    a.atttypid = ANY('{int,int8,int2}'::regtype[]) -- integer type
AND    c.contype = 'p'                                -- PK
AND    array_length(c.conkey, 1) = 1                  -- single column
AND    ad.adsrc = 'nextval('''
            || (pg_get_serial_sequence (a.attrelid::regclass::text, a.attname))::regclass
            || '''::regclass)';

クエリは他のすべてのテーブルで完全に機能します。

私は2014年11月からPostgreSQLと2011年頃からMySQLを使用しているだけなので、AFAIKでできる最善のことは、できるだけ多くの関連データをフェッチすることです。クエリログからdelete_key_bigserialテーブルを作成するために使用されるクエリは次のとおりです。

CREATE TABLE public.delete_key_bigserial (id bigserial PRIMARY KEY NOT NULL)
WITH (OIDS = FALSE);

Erwinのクエリを簡略化し、テーブルで使用して、クエリツールの結果を、クエリが完全に正常に機能するさまざまなテストテーブルと比較しました(4つのdata_typesすべて)。

SELECT * FROM pg_attribute a 
WHERE a.attrelid = 'delete_key_bigserial'::regclass
AND a.attnum > 0
AND NOT a.attisdropped
AND attname='id'
ORDER BY a.attnum;

+----------+---------+----------+---------------+--------+--------+----------+-------------+
| attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff |
+----------+---------+----------+---------------+--------+--------+----------+-------------+
| 46390    | id      | 20       | -1            | 8      | 20     | 0        | -1          |
+----------+---------+----------+---------------+--------+--------+----------+-------------+

+-----------+----------+------------+----------+------------+-----------+--------------+
| atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attisdropped |
+-----------+----------+------------+----------+------------+-----------+--------------+
| -1        | f        | p          | d        | t          | t         | f            |
+-----------+----------+------------+----------+------------+-----------+--------------+

+------------+-------------+--------------+--------+------------+---------------+
| attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions |
+------------+-------------+--------------+--------+------------+---------------+
| t          | 0           |              |        |            |               |
+------------+-------------+--------------+--------+------------+---------------+

Erwinは、他の条件が満たされたときにatttypid列を介してタイプを導出していますが、結果の列/行は、機能する他のテーブルと同じです。主キーのdata_typeが何であるかを判断するために使用した別のカタログテーブルがあるため、次のクエリを使用して、そのテーブルの結果も比較することにしました。

SELECT * FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_name='delete_key_bigserial'
AND is_nullable='NO';

返された列/行(table_name列とcolumn_default列のテーブル名を除く)の唯一の違いは、dtd_identifier列でした。テーブルdelete_key_bigserialは、値dtd_identifierの列20を返します。作業テーブルの場合、クエリは1を返します。 (の下部) PostgreSQL element_typesドキュメント は列を次のように説明します:

要素のデータ型記述子の識別子。これは現在役に立ちません。

これは、単に説明自体を参照することはできますが、レガシー目的のために保持されている非推奨/古いファッションだと思いますか?よくわかりませんが、ここが私がいる場所であり、正しい道を進んでいるとさえ確信していません。

私はむしろ問題に対処し、シナリオから学び、それがテストテーブルであるという理由だけでそれを無視したいと思います。ある日、この問題がテストであるときに対処しなければならないと確信していますnotテーブル。問題が何であるかを追跡するのに役立つ可能性のある関連情報で質問を更新させていただきます。

1
John

このように作成されたテーブルの場合:

CREATE TABLE public.delete_key_bigserial (id bigserial PRIMARY KEY NOT NULL);

... 前の回答の両方のクエリ (およびpgAdmin、psql、またはその他の適切なクライアント)はPK制約を見つけます。そこにない場合は、なんとかして削除しました。
最初のクエリは、PKおよびserialタイプの場合にのみ列を返すことに注意してください。これは例の場合です。

混乱のもう1つの考えられる原因:データベースにdelete_key_bigserialという名前のテーブルが複数ある可能性がありますか?テーブル名は、単一のスキーマ内でのみ一意です。テスト:

SELECT * FROM pg_class WHERE relname = 'delete_key_bigserial';

クエリを明確にするには、テーブル名をスキーマ修飾します。

WHERE  a.attrelid = 'public.delete_key_bigserial'::regclass

ログにDROP CONSTRAINTを残さずに、制約を「非表示」にする方法があります。

  • テーブルを削除して再作成します。
  • スキーマまたはデータベースを削除して再作成します。
  • (一時的に)ステートメントがログに記録されないように log_statement またはその他の関連する設定を設定します。
  • システムカタログを直接(スーパーユーザーとして)操作します。内部的に、主キーはテーブルのcontype = 'p'で設定されます pg_constraint
  • ログファイルを編集します。

  • 等.

2