我有一个有点复杂的场景,我用主键创建的测试表不会返回主键。pgAdmin III 报告没有限制。我有整个 PostgreSQL 查询日志,下面有我用来创建测试表的查询。然后我将主键放在另一个测试表上并使用生成的查询(这不是我手动运行的查询)来帮助我搜索 pgAdmin III 将主键放在有问题的表上但没有找到任何搜索:
ALTER TABLE public.delete_key_bigserial DROP CONSTRAINT
字符串“DROP CONSTRAINT”仅在可追溯到 2014 年 12 月 2 日的查询日志中出现一次,这比我创建测试表还早几周。我现在明白,主键可能会或可能不会被设置为bigserial
或serial
什至创建了一个没有主键的表,将 id 设置为整数,然后设置id
为主键(另一天的蠕虫病毒)。
在较早的问题中,我询问了如何获取data_type
包含的内容,bigserial
或者serial
Erwin Brandstetter 对此有很好的回答。他特别提供了两个查询,一个用于获取data_type
所有列的 s,一个用于获取data_type
主键的 。不幸的是,我一直在测试的其中一个测试表没有返回任何结果。
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 的查询并在表上使用它来将我的查询工具中的结果与查询在(所有四个上)上运行良好的不同测试表进行比较data_type
:
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 | | | | |
+------------+-------------+--------------+--------+------------+---------------+
atttypid
当满足其他条件时,Erwin 通过列派生类型,但是生成的列/行与其他有效的表相同。我在尝试确定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 文档的(底部)将该列描述为:
元素的数据类型描述符的标识符。这目前没有用。
我猜这是一种已弃用/过时的方式,虽然它可以简单地引用描述本身,但仍用于遗留目的?我不确定,但这就是我所在的位置,我什至不确定我是否走在正确的道路上。
我宁愿处理这个问题并从场景中学习,然后仅仅因为它是一个测试表而忽略它,因为有一天我确定当它不是测试表时我将不得不处理这个问题。我很乐意用相关信息更新我的问题,这些信息可能有助于查明问题所在。
对于这样创建的表:
...我在上一个答案中的查询(以及 pgAdmin、psql 或任何其他体面的客户端)都会找到 PK 约束。如果它不存在,则说明您以某种方式将其删除了。请注意,我的第一个查询仅在它是PK和
类型 时才返回该列- 该示例就是这种情况。
serial
造成混淆的另一个可能原因:也许您的数据库中有多个表名
delete_key_bigserial
?表名仅在单个模式中是唯一的。测试:为了使您的查询明确,模式限定表名:
有一些方法可以使约束“消失”而不
DROP CONSTRAINT
在日志中留下 a。log_statement
或其他相关设置,因此不记录该语句。contype = 'p'
在表中设置pg_constraint
。编辑日志文件。
等等