PostgreSQL insert if foreign key exists - postgresql

How can I insert a new row in a table with a foreign key reference only if the foreign key (in this case model) exists?
Currently I have the following statement:
INSERT INTO furniture (model, type) VALUES (modelA, chair)

Use a SELECT that returns nothing if the FK does not exist.
INSERT INTO furniture (model, type)
select 'modelA', 'chair'
where exists (select *
from model
where model.model = 'modelA');
You did not tell us what the referenced table is called. I assumed it's model - you need to adjust that to the real names.

Related

Postgres inheritance and foreign keys or alternative

I use postgres inheritance in my project.
For example: I have a "user" table and "user_child" that inherits from the "user" table.
I have two records: the first record is created in the user table, the second record is created in the user_child table, while the record from user_child is partially stored in user due to inheritance.
I also have a third table - "homework", it has a column assigned_user - a foreign key to the user table.
When I add an record to the "task" table where the "assigned_user" field refers to a record from the user table, then everything is fine, but when I select a record from the user_child table, I get an error:
ERROR: insert or update on table "homework" violates foreign key
constraint "fk-homework-assigned_user""
DETAIL: Key (assigned_user)=(3) is not present in table "user".
Deleting a constraint helps solve my problem, but I want to use cascading deletion and updating records. Can you tell me what alternatives are there or what I'm doing wrong?
PostgreSQL inheritance doesn't quite work how you expect. Yes, you can see info from the child tables when querying the parent table, but this does not extend to foreign key relationships. The row "belongs" to the child, not the parent. The foreign key reference doesn't touch the child.
It's generally a bad idea to use inheritance in PostgreSQL except for specific cases like making a temporal system or enforcing naming conventions (like interfaces in OOP rather than state inheritance).
PostgreSQL inheritance can be very powerful, but it is generally overused in my opinion. There is already a solution (and cross-database compatible) that more closely follows the traditional relational model.
A better model that would do what you seem to want is the following:
CREATE TABLE "user" (
user_id serial PRIMARY KEY, -- Or UUID or generated column in newer versions
-- other fields that all "children" should share
);
CREATE TABLE user_child (
user_id integer NOT NULL
REFERENCES "user" (user_id) ON UPDATE CASCADE ON DELETE CASCADE,
-- other fields specific to the child
);
CREATE TABLE homework (
homework_id serial PRIMARY KEY,
user_id integer NOT NULL
REFERENCES "user" (user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
-- other fields specific to homework
);
The equivalent to your query for user_child is
SELECT u.user_id
FROM "user" AS u
INNER JOIN user_child AS uc;
And to query user, both parent and child would still be
SELECT u.user_id
FROM "user" AS u;
Adding an inner join is pretty trivial and could be hidden behind a view. Now your foreign key reference to "user" will function correctly.

How to use ON CONFLICT with a primary key on a foreign table

I am basically trying to replicate data from a table on one server to another.
I have two identical databases on the servers. I created a foreign table called opentickets_aux1 to represent the opentickets table on the secondary server on the primary server. Both have a primary key of incidentnumber. I can access the data in the foreign table just fine but when I try the following SQL,I get "ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification."
INSERT INTO opentickets_aux1 (SELECT * FROM opentickets)
ON CONFLICT (incidentnumber)
DO
UPDATE SET
status = EXCLUDED.status,
lastmodifieddate = EXCLUDED.lastmodifieddate
I want to update a few columns if the primary key exist. I use this statement for other queries and they work when its a local table. Any ideas?
A foreign table cannot have a primary key constraint, because PostgreSQL wouldn't be able to enforce its integrity. Therefore, you cannot use INSERT ... ON CONFLICT with foreign tables.
Your idea also does not handle rows that are deleted on the foreign server, but maybe that's intentional.
If you want a local copy of a foreign table, the easiest way would be to create a materialized view on the foreign table.
If that is not your desire (perhaps because you don't want to copy deletions), you'd have to use statements like
INSERT INTO localtable
SELECT * FROM foreigntable f
WHERE NOT EXISTS
(SELECT 1 FROM localtable l
WHERE f.id = l.id);
UPDATE localtable l
SET /* all columns from f */
FROM foreigntable f
WHERE f.id = l.id
AND (f.*) <> (l.*);

Can I have a foreign key to a parent table in PostgreSQL?

I'm using inheritance and I ended up having a problem.
If I run:
select count(*) from estate_properties where id = 86820;
I get 1.
But when I try to run this:
insert into property_images (binary_image, name, property_id) values (16779, 'IMG_0096.jpg', 86820)
I get:
********** Error **********
ERROR: insert or update on table "property_images" violates foreign
key constraint "property_images_property_id_fkey" SQL state: 23503
Detail: Key (property_id)=(86820) is not present in table
"estate_properties".
Also ID on estate_properties is SERIAL.
Note: Another table apartments inherits from estate_properties, and 86820 was added to it. Would that make a difference? Also why would it I still have the ID in the parent table and I can select if from there.
Edit:
Looking more closely at the documentation:
http://www.postgresql.org/docs/9.5/static/ddl-inherit.html
I want to achieve this:
5.9.1. Caveats
Specifying that another table's column REFERENCES cities(name) would
allow the other table to contain city names, but not capital names.
There is no good workaround for this case.
EDIT2:
Here is the declaration of the foreign key:
CONSTRAINT property_images_property_id_fkey FOREIGN KEY (property_id)
REFERENCES estate_properties (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
Apparently the answer is here:
Foreign keys + table inheritance in PostgreSQL?
A foreign key can point to a table that is part of an inheritance hierarchy, but it'll only find rows in that table exactly. Not in any parent or child tables. To see which rows the foreign key sees, do a SELECT * FROM ONLY thetable. The ONLY keyword means "ignoring inheritance" and that's what the foreign key lookup will do

Is there a way to set EF entity reference names from the database?

Is there a way to set entity reference names from the database?
I’m using database first.
I have a table with multiple foreign keys to the same table
(Address) as shown below.
EF creates entity relations for the 2 addresses and sets the names
to AddressReference and Address1Reference which is not as
descriptive as I would like.
I know I can do this from the EF side with annotations but is there a way to set the entity reference names from the database?
CREATE TABLE [dbo].[Person] (
[ID] INT PRIMARY KEY IDENTITY NOT NULL,
[Name] NVARCHAR(50) NOT NULL,
[HomeAddressID] INT,
[WorkAddressID] INT
)
GO
CREATE INDEX [IX_Person_HomeAddressID] ON [dbo].[Person] ([HomeAddressID])
GO
CREATE INDEX [IX_Person_WorkAddressID] ON [dbo].[Person] ([WorkAddressID])
GO
ALTER TABLE [dbo].[Person] ADD CONSTRAINT [FK_Person_HomeAddressID] FOREIGN KEY ([HomeAddressID]) REFERENCES [Address] ([HomeAddressID])
GO
ALTER TABLE [dbo].[Person] ADD CONSTRAINT [FK_Person_WorkAddressID] FOREIGN KEY ([WorkAddressID]) REFERENCES [Address] ([WorkAddressID])
GO
No, using database first, you will need to update the navigation names in the data model by-hand.
Of course you could modify the T4 file to generate a different navigation name (it uses the FK table name by default).

Adding Foreign Key, SQL SERVER 2008

I am trying to add a foreign key to a table, and it give me the following error:
There are no primary or candidate keys in the referenced table 'tbl_Person' that match the referencing column list in the foreign key 'P_ID'.
I have a tbl_Person, which is defined as:
P_ID INT (Primary Key)
f_Name,
l_Name
the other table is a comments table which is defined as:
C_ID INT,
Comments,
P_ID (should be the foreign key)
Trying to make a one to many relationship table, so when the user add a comment, it is referenced back to him, also, he can add onto the comments without initializing a new comment. Hopefully that makes a little sense.
Ex: Randy Bing enter "I love SQL", his ID is 1, f_Name is Randy, l_Name is Bing, his comments are "I love Sql". His comments should store a unique ID, as well as import his P_ID.
Later on when Randy wants to add onto the comment with the same C_ID where P_ID matches him without creating a new C_ID.
Here is the Code:
ALTER TABLE tbl_Comments
ADD CONSTRAINT P_ID
FOREIGN KEY (P_ID)
REFERENCES tbl_Person(P_ID)
Am I close to being on the right track?
This error usually means the datatypes are different between "Comments" and "Person", assuming this is the actual message
The SQL should be this
ALTER TABLE tbl_Comments WITH CHECK ADD
CONSTRAINT FK_Comments_Person FOREIGN KEY (P_ID) REFERENCES tbl_Person (P_ID)
This matches what you added. So:
check datatypes are both int
ensure P_ID is primary key on tbl_Person
(Edit, Dec 2011) collation and length must be the same for varchar columns too
In Object Explorer, connect to an instance of Database Engine.
On the Standard bar, click New Query.
The example creates a foreign key on the column TempID and references the column SalesReasonID in the Sales.SalesReason table.
USE AdventureWorks2012;
GO
ALTER TABLE Sales.TempSalesReason
ADD CONSTRAINT FK_TempSales_SalesReason FOREIGN KEY (TempID)
REFERENCES Sales.SalesReason (SalesReasonID)
ON DELETE CASCADE
ON UPDATE CASCADE
;
GO
the name of your constraint, p_id,
clashes with the name of the p_id column