Eu tenho um cenário um tanto complicado em que uma tabela de teste que criei com uma chave primária não retornará a chave primária. O pgAdmin III informa que não há restrições. Eu tenho todo o log de consulta do PostgreSQL e abaixo tenho a consulta que usei para criar a tabela de teste. Em seguida, soltei a chave primária em uma tabela de teste diferente e usei a consulta gerada (ainda não é uma consulta que executei manualmente) para me ajudar a pesquisar pgAdmin III soltando a chave primária na tabela em questão e não encontrei nada procurando por:
ALTER TABLE public.delete_key_bigserial DROP CONSTRAINT
A string 'DROP CONSTRAINT' aparece apenas uma vez no log de consulta desde 02/12/2014, semanas antes de eu criar as tabelas de teste. Agora entendo que uma chave primária pode ou não ser definida como bigserial
ou serial
até mesmo criou uma tabela sem uma chave primária definida como id para inteiro e, em seguida, definida id
como a chave primária (outra lata de worms para todo 'outro dia ).
Em uma pergunta anterior , perguntei sobre como buscar a data_type
inclusão se fosse bigserial
ou serial
para a qual Erwin Brandstetter tinha uma excelente resposta. Ele forneceu duas consultas em particular, uma para buscar os data_type
s para todas as colunas e outra para buscar a data_type
chave primária. Infelizmente, uma das tabelas de teste com as quais tenho testado não está retornando nenhum resultado.
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)';
A consulta funciona perfeitamente em todas as outras tabelas.
Eu só trabalho com PostgreSQL desde novembro de 2014 e MySQL desde cerca de 2011, então a melhor coisa que posso fazer AFAIK é buscar o máximo de dados relevantes que puder. Aqui está a consulta usada para criar a delete_key_bigserial
tabela a partir do log de consulta:
CREATE TABLE public.delete_key_bigserial (id bigserial PRIMARY KEY NOT NULL)
WITH (OIDS = FALSE);
Simplifiquei a consulta de Erwin e usei-a na tabela para comparar os resultados em minha ferramenta de consulta com diferentes tabelas de teste nas quais a consulta funciona perfeitamente bem (em todos os quatro data_type
s):
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 está derivando o tipo por meio da atttypid
coluna quando outras condições são atendidas, no entanto, a coluna/linha resultante é idêntica a outras tabelas que funcionam. Há outra tabela de catálogo que usei em minhas tentativas de determinar qual data_type
é a chave primária, então decidi comparar os resultados dessa tabela também por meio da seguinte consulta:
SELECT * FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_name='delete_key_bigserial'
AND is_nullable='NO';
A única diferença para qualquer coluna/linha retornada (além do nome da tabela nas colunas table_name
e ) era a coluna. A tabela retorna a coluna com o valor , para uma tabela de trabalho a consulta retorna . A (parte inferior da) documentação element_types do PostgreSQL descreve a coluna como:column_default
dtd_identifier
delete_key_bigserial
dtd_identifier
20
1
Um identificador do descritor de tipo de dados do elemento. Atualmente, isso não é útil.
Eu estou supondo que esta é uma moda obsoleta/antiga que é mantida para propósitos herdados, embora possa simplesmente se referir à própria descrição? Não tenho certeza, mas é aqui que estou e nem tenho certeza se estou no caminho certo.
Prefiro lidar com o problema e aprender com o cenário do que desconsiderá-lo simplesmente porque é uma tabela de teste, pois um dia tenho certeza que terei que lidar com esse problema quando não for uma tabela de teste. Ficarei feliz em atualizar minha pergunta com informações relevantes que podem ajudar a rastrear qual é o problema.
Para uma tabela criada assim:
... ambas as minhas consultas na resposta anterior (assim como pgAdmin, psql ou qualquer outro cliente decente) encontrariam a restrição PK. Se não estiver lá, você o removeu de alguma forma .
Observe que minha primeira consulta só retorna a coluna se for o PK e um
serial
tipo - que é o caso do exemplo.Outra causa possível para a confusão: talvez você tenha mais de uma tabela nomeada
delete_key_bigserial
em seu banco de dados? Os nomes das tabelas são exclusivos apenas dentro de um único esquema. Teste com:Para tornar sua consulta inequívoca, qualifique o esquema do nome da tabela:
Existem maneiras de fazer a restrição "desaparecer" sem deixar um
DROP CONSTRAINT
em seus logs.log_statement
ou outras configurações relevantes para que a instrução não seja registrada.contype = 'p'
na tabelapg_constraint
.Edite os arquivos de registro.
etc.