Cause of PostgreSQL foreign key violation? - postgresql

My PostgreSQL (9.2) database contains two tables registrations and attributes with a foreign key constraint:
postgres=# \d+ registrations;
Table "public.registrations"
Column | Type | Modifiers | Storage | Stats target | Description
---------+-------+-----------+----------+--------------+-------------
name | text | not null | extended | |
parent | text | | extended | |
storage | bytea | | extended | |
Indexes:
"registrations_pkey" PRIMARY KEY, btree (name)
Referenced by:
TABLE "attributes" CONSTRAINT "attributes_cname_fkey" FOREIGN KEY (cname) REFERENCES registrations(name) ON DELETE CASCADE
Has OIDs: no
postgres=# \d+ attributes;
Table "public.attributes"
Column | Type | Modifiers | Storage | Stats target | Description
--------+-------+-----------+----------+--------------+-------------
cname | text | not null | extended | |
aname | text | not null | extended | |
tags | text | | extended | |
value | bytea | | extended | |
Indexes:
"attributes_pkey" PRIMARY KEY, btree (cname, aname)
Foreign-key constraints:
"attributes_cname_fkey" FOREIGN KEY (cname) REFERENCES registrations(name) ON DELETE CASCADE
Has OIDs: no
At some point I realised that some rows violated the foreign key constraint:
postgres=# SELECT COUNT(*) FROM attributes LEFT JOIN registrations ON attributes.cname=registrations.name WHERE registrations.name IS NULL;
count
-------
71
(1 row)
Could you help me understand how this corruption could happen?

A constraint marked as NOT VALID is the one case you might expect to see violations, but the NOT VALID clause would show up in the psql \d+ output. (I believe it's possible to manually update this flag in the catalog, but I hope for your sake that this isn't the issue...)
As far as I know, the only supported way of bypassing a foreign key check is to SET session_replication_role TO replica before modifying the data. This is there for the benefit of replication processes, operating under the assumption that the constraint has already been validated on the master - though this can certainly go wrong if your replicator is buggy or misconfigured.
It's also possible for a superuser to manually disable the constraint's underlying triggers (and it's often tempting for someone trying to speed up a bulk import). The following will tell you if the triggers are currently active (tgenabled should be 'O'):
SELECT *
FROM pg_trigger
WHERE tgname ~ '^RI_ConstraintTrigger'
AND tgrelid IN ('registrations'::regclass, 'attributes'::regclass)
I don't think there's any way of knowing whether this was temporarily changed in the past, though if you have statement logging enabled, you might find an ALTER TABLE ... DISABLE TRIGGER statement in there somewhere.
There is also at least one loophole in the foreign key enforcement, and of course, it's always possible that you've found a bug...

This can happen if the FK contraint was created with a NOT VALID clause (don't do this):
CREATE TABLE one
( one_id INTEGER NOT NULL PRIMARY KEY
);
CREATE TABLE two
( two_id INTEGER NOT NULL PRIMARY KEY
, one_id INTEGER NOT NULL
);
INSERT INTO one(one_id)
SELECT gs FROM generate_series(0,12,2) gs;
INSERT INTO two(two_id,one_id)
SELECT gs, gs FROM generate_series(0,12,3) gs;
ALTER TABLE two
ADD CONSTRAINT omg FOREIGN KEY (one_id) references one(one_id)
-- DEFERRABLE INITIALLY DEFERRED
NOT VALID
;

Related

show postgresql database schema

I want to show something like this with PostgreSQL but I don't know what I must searching for
can you explain to me how to show something like this with PostgreSQL ?
The image you shared is a graphical layout of tables. PostgreSQL doesn't produce such output, but you can get the layout of individual tables by running \d <tablename> in psql. This will provide you with the list of columns, column types, constraints, primary key, foreign keys and comments.
For example:
postgres=# \d catalogue
Table "public.catalogue"
Column | Type | Collation | Nullable | Default
-------------+---------+-----------+----------+---------------------------------------
id | integer | | not null | nextval('catalogue_id_seq'::regclass)
item | name | | |
qty | integer | | |
description | text | | |
Indexes:
"catalogue_pkey" PRIMARY KEY, btree (id)
Alternatively, if you require a GUI-based solution, check out PgAdmin: https://www.pgadmin.org/
You can use dbeaver for this, using View Diagram option clicking in you schema

Unable to insert a row in Postgres database "ERROR: duplicate key value violates unique constraint" although there is no entry present in the table

I have a table with schema :
Table: "public.system_configuration_parameter"
Column | Type | Collation | Nullable | Default
---------------+-----------------------------+-----------+----------+--------------------------------------------------
id | integer | | not null | nextval('system_configuration_id_seq'::regclass)
name | character varying | | not null |
type | character varying | | not null |
value | character varying | | |
default_value | character varying | | not null |
date_added | timestamp without time zone | | not null | now()
date_modified | timestamp without time zone | | not null | now()
Indexes:
"system_configuration_parameter_pkey" PRIMARY KEY, btree (id)
"system_configuration_parameter_name_key" UNIQUE CONSTRAINT, btree (name)
The following query results into ERROR:
insert into system_configuration_parameter (name, type, value ,default_value) values ('serverPerformanceMode','String','standardMode','standardMode');
ERROR: duplicate key value violates unique constraint "system_configuration_parameter_name_key"
DETAIL: Key (name)=(serverPerformanceMode) already exists.
The thing is there is no entry present in a table with name value as 'serverPerformanceMode'
shubhdb=# select value from system_configuration_parameter where name = ('serverPerformanceMode');
(0 rows)
I am using postgres 9.3, I have performed a migration of postgres to upgraded version 10. I currently have both the versions installed in my system.
I used to use the same database with the same structure and it used to work perfectly fine before. This even works fine with postgres-10 now, the problem occurs only when I use postgres-9.3 with the same build.
Does anyone have any idea about this? or has faced the same issue?
Thank you for reading.
This type of problem is usually caused by user error. You are probably connecting to one database to do the insert, and a different one to do the query (or perhaps different schema's of the same database). Can you make your code which does the insertion follow-up the error by running the query, using the same connection object, rather than running the query manually over a different connection?

Is it necessary for the Ecto schema and the SQL database to have the same foreign keys?

When I use the references keyword to generate schema I notice that in the actual database the corresponding column does not have list the column as a foreign key.
E.g. lets say we call (in our console):
mix phx.gen.html Multimedia Video videos user_id:references:users \
url:string title:string description:text
This generates a table in pgsql which looks like this:
Notice how user_id doesn't have [FK] in the column name. And looking at the properties of there are no foreign keys too.
My question is: is it necessary to have the ecto schema and sql database indicate the same foreign keys? In Phoenix, we use belongs_to :user, Rumbl.Accounts.User in the schema for videos to indicate a foreign key. But looking at the database you can't really infer that.
TL;DR
It is not strictly necessary to have the relationships defined on the database level. Ecto associations will work even if the database has no idea tables are related and when no foreign key indices and constraints were defined.
Having said that, relations, properly defined on the database level have many benefits, such as referential integrity, better performance, and added functionality available when changes are applied to the data. Therefore, although it is possible to skip these, it is hardly recommended.
Now some explanations about the database objects you see. Here are the migration and the schema, generated by the command you mentioned,
mix phx.gen.html Multimedia Video videos user_id:references:users url:string title:string description:text
# in priv/repo/migrations/<timestamp>_create_videos.exs
def change do
create table(:videos) do
add :url, :string
add :title, :string
add :description, :text
add :user_id, references(:users, on_delete: :nothing)
timestamps()
end
create index(:videos, [:user_id])
end
# in lib/app/multimedia/video.ex
schema "videos" do
field :description, :string
field :title, :string
field :url, :string
field :user_id, :id
timestamps()
end
Note that the migration includes the references definition while the schema does not mention any relation to users. As you pointed out, the schema does need to be modified to include the association belongs_to :user (User schema on the other side also needs to be updated).
Nevertheless, the table definition resulted from this migration does indeed include the foreign key specification:
shell> psql -h localhost -U postgres -d db_name
psql> \d videos
# output
Table "public.videos"
Column | Type | Collation | Nullable | Default
-------------+--------------------------------+-----------+----------+------------------------------------
id | bigint | | not null | nextval('videos_id_seq'::regclass)
url | character varying(255) | | |
title | character varying(255) | | |
description | text | | |
user_id | bigint | | |
inserted_at | timestamp(0) without time zone | | not null |
updated_at | timestamp(0) without time zone | | not null |
Indexes:
"videos_pkey" PRIMARY KEY, btree (id)
"videos_user_id_index" btree (user_id)
Foreign-key constraints:
"videos_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
You can get this output from psql, the command line postgres client. Other (GUI) clients out there may or may not implement support for everything you need to know about your database, so it is best to use the definitive toolset as #KonstantinStrukov pointed out.

PostgreSQL - insert statement error, thinks value to insert is a column name

I'm running PostgreSQL version 9.5.1 on my Mac - I'm trying to make a simple insert statement, but it's spitting an error that I don't quite understand... for some reason, it seems to think that one of the values that I'm inserting is actually one of the column names. Here's the scenario...
\d+ group_members
Column | Type |
------------+-----------------------------+
id | integer |
group_id | integer |
user_id | integer |
role | character varying(255) |
inserted_at | timestamp without time zone |
updated_at | timestamp without time zone |
Indexes:
"group_members_pkey" PRIMARY KEY, btree (id)
"group_members_group_id_index" btree (group_id)
"group_members_user_id_index" btree (user_id)
When I try to run
insert into group_members (group_id, user_id, role, inserted_at, updated_at)
values (1, 2, ’member’, current_timestamp, current_timestamp);
I get the error:
ERROR: column "’member’" does not exist
LINE 1: ...user_id,role,inserted_at,updated_at) values (1,2,’member’,c...
^
Well yes, I agree, the column 'member' does not exist... but I'm not sure I understand why PostgreSQL thinks that this is my intention. I have made numerous inserts into other tables and had now such problem but I can't seem to insert into this table. Can anyone see where I've gone wrong?
Replace ’member’ with 'member' .
It seems you dont have single quote. it is some other char

Keeping a table column empty when it is indexed as unique

Is it possible to keep a table column empty if it's defined as unique?
Table schema
Column | Type | Modifiers | Description
-------------------+------------------------+---------------+-------------
id | integer | not null |
name | character varying(64) | |
Indexes
Indexes:
"clients_pkey" PRIMARY KEY, btree (id)
"clients_name_idx" UNIQUE, btree (name)
Has OIDs: yes
Due to modifications to the application sometimes the name column needs to be empty, is this possible at all?
If the column can contain NULL values, then that is OK, as NULL is not included in the index.
Note that some databases don't implement the standard properly (some versions of SQL Server only allowed one NULL value per unique constraint, but I'm sure if that is still the case).
Using NULL is the better option, but you could also use a conditional unique index:
CREATE UNIQUE INDEX unique_clients_name ON clients (name) WHERE name <> '';
And avoid oid's, these are useless and obsolete.