Table A is a kind of unique sequence for all my tables.
-- Table: public."IdCentral"
-- DROP TABLE public."IdCentral";
CREATE TABLE public."IdCentral"
(
"Id" bigint NOT NULL DEFAULT nextval('"IdCentral_Id_seq"'::regclass),
"Tag" character varying(127) COLLATE pg_catalog."default",
CONSTRAINT "IdCentral_pkey" PRIMARY KEY ("Id")
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
Table B is any table of my database
-- Table: public."Users"
-- DROP TABLE public."Users";
CREATE TABLE public."Users"
(
"Id" bigint NOT NULL,
"Login" character varying(30) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT "Users_pkey" PRIMARY KEY ("Id"),
CONSTRAINT "PK" FOREIGN KEY ("Id")
REFERENCES public."IdCentral" ("Id") MATCH FULL
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public."Users"
OWNER to dba;
When I want to insert into B, I need to create a new record in A passing the B Table name as Tag.
What you want is CURRVAL:
SELECT CURRVAL('IdCentral_Id_seq');
... which will give you the current value for the ID sequence after insert. For safety, it's best to use it inside a transaction, especially if you're combining it with load-balancing:
BEGIN;
INSERT INTO "a" ...
INSERT INTO "b" VALUES ( CURRVAL('IdCentral_Id_seq', ... )
COMMIT;
That being said, it appears that you're implementing a "universal ID" system for your database. This is something every new DBA tries (I did), and it's inevitably a bad idea which you end up spending a lot of time refactoring out later. If there's some reason you genuinely need some kind of universal ID, consider using a UUID instead.
Related
I try to create code for postgresql
CREATE TABLE kaart (
kaartid integer NOT NULL,
naam character varying,
saldo real,
kaarthouderid integer
);
CREATE TABLE kaart_product (
kaartkaartid integer,
productid2 integer
);
CREATE TABLE kaarthouder (
id integer NOT NULL,
naam character varying(255),
naw character varying(255),
geslacht "char"
);
CREATE TABLE product (
naam character varying,
id integer NOT NULL
);
ALTER TABLE ONLY kaart
ADD CONSTRAINT kaart_pkey PRIMARY KEY (kaartid);
ALTER TABLE ONLY kaarthouder
ADD CONSTRAINT kaarthouder_pkey PRIMARY KEY (id);
ALTER TABLE ONLY product
ADD CONSTRAINT product_pkey PRIMARY KEY (id);
ALTER TABLE ONLY kaart
ADD CONSTRAINT kaartco FOREIGN KEY (kaartid) REFERENCES kaarthouder(id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY kaart_product
ADD CONSTRAINT kaartkaartidco FOREIGN KEY (kaartkaartid) REFERENCES kaart(kaartid) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY kaart_product
ADD CONSTRAINT productidco FOREIGN KEY (kaartkaartid) REFERENCES product(id) ON UPDATE CASCADE ON DELETE CASCADE;
INSERT INTO kaart VALUES (1, 'Sander',50.00 ,1);
INSERT INTO kaart_product VALUES (1,1);
INSERT INTO kaarthouder VALUES (1, 'Sander','test,testing','man');
INSERT INTO product VALUES ('studentenproduct',1);
But whenever i try to run it it gives me this error:
23503: insert or update on table "kaart" violates foreign key constraint "kaartco"
But i really dont know why this happens since it is the same to the other foreign keys that are below it
So can someone help me fix this?
You try to link to a product and a kaart that doesn't exist yet.
Move:
INSERT INTO kaart_product VALUES (1,1);
Two lines down under:
INSERT INTO product VALUES ('studentenproduct',1);
That should do the job for you.
Try to search google for forgein key contstraints and how they work.
I can imagine that it is unlikely that this question has never been answered. However, I have not found it, so in any case here is my problem:
I am migrating from MySQL.
I am getting an error when I try to create a table with one single data field with 2 foreign keys referencing another table.
My goal is to simply have a phone directory for employees.
The directory table must reference the employee id as well as the phone number type.
I get this error when trying to do so:
ERROR: There is no unique constraint matching given keys, for referenced table: Employees!
Here is my current sql dump:
-- ----------------------------
-- Table structure for EmployeeGroups
-- ----------------------------
DROP TABLE IF EXISTS "public"."EmployeeGroups";
CREATE TABLE "public"."EmployeeGroups" (
"Id" int8 DEFAULT nextval('"EmployeeGroups_Id_seq"'::regclass) NOT NULL,
"EmployeeGroup" varchar(255) COLLATE "default"
)
WITH (OIDS=FALSE)
;
-- ----------------------------
-- Table structure for Employees
-- ----------------------------
DROP TABLE IF EXISTS "public"."Employees";
CREATE TABLE "public"."Employees" (
"Id" int8 DEFAULT nextval('"Employees_Id_seq"'::regclass) NOT NULL,
"EmployeeGroupId" int8 DEFAULT
nextval('"Employees_EmployeeGroupId_seq"'::regclass) NOT NULL,
"FirstName" varchar(255) COLLATE "default",
"LastName" varchar(255) COLLATE "default",
"CivicNumber" int4,
"CivicNumberAlias" int4,
"StreetName" varchar(255) COLLATE "default",
"City" varchar(255) COLLATE "default",
"PostalCode" varchar(255) COLLATE "default",
"UserAcessLevel" int8 DEFAULT
nextval('"Employees_UserAcessLevel_seq"'::regclass) NOT NULL,
"Username" varchar(255) COLLATE "default",
"Password" varchar(255) COLLATE "default",
"Timestamp" date
)
WITH (OIDS=FALSE)
;
-- ----------------------------
-- Table structure for PhoneNumberType
-- ----------------------------
DROP TABLE IF EXISTS "public"."PhoneNumberType";
CREATE TABLE "public"."PhoneNumberType" (
"Id" int8 DEFAULT nextval('"PhoneNumberType_Id_seq1"'::regclass) NOT NULL,
"PhoneNumberType" varchar(150) COLLATE "default" NOT NULL
)
WITH (OIDS=FALSE)
;
-- ----------------------------
-- Table structure for SystemAcessLevel
-- ----------------------------
DROP TABLE IF EXISTS "public"."SystemAcessLevel";
CREATE TABLE "public"."SystemAcessLevel" (
"Id" int8 DEFAULT nextval('"SystemAcessLevel_Id_seq"'::regclass) NOT NULL,
"AcessLevel" varchar(255) COLLATE "default" NOT NULL
)
WITH (OIDS=FALSE);
Here is my error generating statement:
CREATE TABLE "public"."NewTable" (
"Id" serial8 NOT NULL,
"EmployeeId" int8 NOT NULL,
"PhoneNumberTypeId" int8 NOT NULL,
"PhoneNumber" varchar(16) NOT NULL,
PRIMARY KEY ("Id"),
CONSTRAINT "phone_fk_emp_id" FOREIGN KEY ("EmployeeId")
REFERENCES "public"."Employees" ("Id") ON DELETE NO ACTION ON UPDATE
CASCADE,
CONSTRAINT "phone_fk_type_id" FOREIGN KEY ("PhoneNumberTypeId")
REFERENCES "public"."PhoneNumberType" ("Id") ON DELETE NO ACTION ON
UPDATE CASCADE
)
WITH (OIDS=FALSE)
;
As it turns out the problem was identifying the
EmployeeGroupId
field that was referenced in the Employees table as a second primary key created a conflict when adding the EmployeeDirectory table referencing the same foreing key as a second primary key of the Employees.GroupId field.
In other word seems like PostgreSQL considers second primary key as unique identifiers creating a one to one relationship therefore it considers it as an error to have an additional table referencing the same identifier as a foreing key stated as a second primary key, and please correct me if I am wrong since not an expert when it comes to PostgreSQL.
This however is accepted by Mysql; this is why I was having a hard time figuring out this error.
Every column (or set of columns) that you reference in a foreign key must have a primary key or unique constraint on it.
Otherwise, how could you identify which row the foreign key points to?
I am trying to import data to a table using COPY from a csv file. This is the table in which I want to import:
CREATE TABLE public.forms_member_registration
(
baseformmodel_ptr_id integer NOT NULL,
"Agrihub" character varying(200) NOT NULL,
"Ward_Number" character varying(300) NOT NULL,
"Area" character varying(300) NOT NULL,
"First_Name" character varying(300) NOT NULL,
"Last_Name" character varying(300) NOT NULL,
"Other_Name" character varying(300) NOT NULL,
-----------snip--------------------------------
"L3_Modules_Completed" character varying(200),
"L3_Specify_Other" character varying(300) NOT NULL,
gps_location geometry(Point,4326),
CONSTRAINT forms_member_registration_pkey
PRIMARY KEY (baseformmodel_ptr_id),
CONSTRAINT baseformmodel_ptr_id_refs_id_c03f6c72
FOREIGN KEY (baseformmodel_ptr_id)
REFERENCES public.forms_baseformmodel (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
The primary key is referencing this table:
CREATE TABLE public.forms_baseformmodel
(
id integer NOT NULL DEFAULT nextval('forms_baseformmodel_id_seq'::regclass),
user_id integer NOT NULL,
created_at timestamp with time zone NOT NULL,
CONSTRAINT forms_baseformmodel_pkey
PRIMARY KEY (id),
CONSTRAINT user_id_refs_id_3a410ec9
FOREIGN KEY (user_id)
REFERENCES public.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
I am using this copy command:
COPY forms_member_registration("Agrihub", "Ward_Number", "Area","First_Name", "Last_Name", "Other_Name", "SA_ID_Number", "Gender", "Phone_Number") FROM '/opt/project/migration/file-3.csv' DELIMITER ',' CSV HEADER;
Giving this error:
ERROR: null value in column "baseformmodel_ptr_id" violates not-null constraint
So the problem as I see it is that "baseform_ptr_id" needs to be retrieved from the id column of the forms_baseformmodel table for each entry but id only gets created when an entry is made to forms_baseformmodel.
How can I create the entry in forms_baseformmodel, retrieve it and add it to the tuple being copied?
Hope that makes sense... This is all kinda new for me.
Thanks in advance
This is a rather common problem. What you must do is:
COPY the data to a TEMPORARY or UNLOGGED table;
INSERT INTO real_table SELECT ... FROM temp_table INNER JOIN other_table ...
In other words, copy to a staging table, then generate the real data set with a join and insert the join product into the real table.
It's somewhat related to the bulk upsert problem.
So in your case you'd create a temp_forms_member_registration, copy the csv into it including the user_id column you wish to replace, then:
INSERT INTO forms_member_registration(
baseformmodel_ptr_id,
"Agrihub",
...
)
SELECT
fbfm.id,
tfmr."Agrihub",
...
FROM temp_forms_member_registration tfmr
INNER JOIN forms_baseformmodel ON (tfmr.user_id = fbfm.user_id);
I have three tables: ModelingAgency.clients, ModelingAgency.models, ModelingAgency.Bookings. All three tables have a primary key column called id.
The table bookings has two columns that reference clients and models. In pgAdmin when I try to create a foreign key in bookings to either clients or models I get the following screens:
What am I overlooking here? I am new to PostgreSQL (This is my first test project with PostgreSQL -- I've always used MySQL and occasionally SQL Server) so it's probably something obvious (I just don't see it).
EDIT: Here is the DDL, as requested:
-- Table: "ModelingAgency.bookings"
-- DROP TABLE "ModelingAgency.bookings";
CREATE TABLE "ModelingAgency.bookings"
(
id integer NOT NULL DEFAULT nextval('"ModelingAgency.Bookings_id_seq"'::regclass),
"clientId" integer NOT NULL,
"modelId" integer NOT NULL,
"time" timestamp with time zone NOT NULL DEFAULT now(),
"location" character varying(100) NOT NULL DEFAULT 'No Location Selected'::character varying,
CONSTRAINT "bookingId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.bookings" OWNER TO "MyBatisTutorial";
-- Table: "ModelingAgency.clients"
-- DROP TABLE "ModelingAgency.clients";
CREATE TABLE "ModelingAgency.clients"
(
id integer NOT NULL DEFAULT nextval('"ModelAgency.clients_id_seq"'::regclass),
"name" character varying(45) NOT NULL,
CONSTRAINT "clientId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.clients" OWNER TO "MyBatisTutorial";
-- Table: "ModelingAgency.models"
-- DROP TABLE "ModelingAgency.models";
CREATE TABLE "ModelingAgency.models"
(
id serial NOT NULL,
"name" character varying(45) NOT NULL,
CONSTRAINT "modelId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.models" OWNER TO "MyBatisTutorial";
Looking into your posted DDL code I see that your table's names are written in wrong way (that causes your issue with pgAdmin):
"ModelingAgency.bookings"
It should be in format "schema"."tableName":
"ModelingAgency"."bookings"
After that Object browser looks like this (probably you need to create schema first using easily pgAdmin or with CREATE SCHEMA SQL statement):
Here is working DDL code (I omitted some things like OIDS and OWNER TO, but that doesn't matter to your case, BTW OIDS are false on default):
DROP TABLE IF EXISTS "ModelingAgency"."bookings";
CREATE TABLE "ModelingAgency"."bookings"
(
id serial,
"clientId" integer NOT NULL,
"modelId" integer NOT NULL,
"time" timestamp with time zone NOT NULL DEFAULT now(),
"location" character varying(100) NOT NULL
DEFAULT 'No Location Selected'::character varying,
CONSTRAINT "bookingId" PRIMARY KEY (id)
);
DROP TABLE IF EXISTS "ModelingAgency"."clients";
CREATE TABLE "ModelingAgency"."clients"
(
id serial,
"name" character varying(45) NOT NULL,
CONSTRAINT "clientId" PRIMARY KEY (id)
);
DROP TABLE IF EXISTS "ModelingAgency"."models";
CREATE TABLE "ModelingAgency"."models"
(
id serial NOT NULL,
"name" character varying(45) NOT NULL,
CONSTRAINT "modelId" PRIMARY KEY (id)
)
I am struggling with foreign keys in my DB, possibly it has something to do with inheritance?
So here's the basic setup:
-- table address
CREATE TABLE address
(
pk_address serial NOT NULL,
fk_gadmid_0 integer NOT NULL, -- this table already exists, no problem here
street character varying(100),
zip character varying(10),
city character varying(50),
public boolean,
CONSTRAINT address_primarykey PRIMARY KEY (pk_address),
CONSTRAINT gadmid_0_primarykey FOREIGN KEY (fk_gadmid_0)
REFERENCES adm0 (gadmid_0) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE address OWNER TO postgres;
-- table stakeholder (parent)
CREATE TABLE stakeholder
(
pk_stakeholder integer DEFAULT nextval('common_stakeholder_seq') NOT NULL,
fk_stakeholder_type integer NOT NULL, -- this table also exists, no problem here
name character varying(255) NOT NULL,
CONSTRAINT stakeholder_primarykey PRIMARY KEY (pk_stakeholder),
CONSTRAINT stakeholder_fk_stakeholder_type FOREIGN KEY (fk_stakeholder_type)
REFERENCES stakeholder_type (pk_stakeholder_type) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE stakeholder OWNER TO postgres;
-- table individual (child of stakeholder)
CREATE TABLE individual
(
firstname character varying(50),
fk_title integer, -- this table also exists, no problem here
email1 character varying (100),
email2 character varying (100),
phone1 character varying (50),
phone2 character varying (50),
CONSTRAINT individual_primarykey PRIMARY KEY (pk_stakeholder),
CONSTRAINT title_foreignkey FOREIGN KEY (fk_title)
REFERENCES title (pk_title) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (stakeholder)
WITH (
OIDS=FALSE
);
ALTER TABLE individual OWNER TO postgres;
-- link between stakeholder and address
CREATE TABLE l_stakeholder_address
(
pk_l_stakeholder_address serial NOT NULL,
fk_stakeholder integer NOT NULL REFERENCES stakeholder,
fk_address integer NOT NULL REFERENCES address,
CONSTRAINT l_stakeholder_address_primarykey PRIMARY KEY (pk_l_stakeholder_address),
CONSTRAINT l_stakeholder_address_fk_stakeholder FOREIGN KEY (fk_stakeholder)
REFERENCES stakeholder (pk_stakeholder) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE NO ACTION,
CONSTRAINT l_stakeholder_address_fk_address FOREIGN KEY (fk_address)
REFERENCES address (pk_address) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE l_stakeholder_address OWNER TO postgres;
So far, no problem. Then I tried to add some values:
INSERT INTO individual (pk_stakeholder, fk_stakeholder_type, name, firstname, fk_title, email1, email2, phone1, phone2)
VALUES (1, 8, 'Lastname', 'Firstname', 1, 'me#you.com', '', '', '');
INSERT INTO address (pk_address, fk_gadmid_0, street, zip, city, public)
VALUES (1, 126, 'Address', '', 'City', FALSE);
INSERT INTO l_stakeholder_address (pk_l_stakeholder_address, fk_stakeholder, fk_address)
VALUES (DEFAULT, 1, 1);
And finally I end up having an error (SQL state 23503) saying that the key (fk_stakeholder)=(1) is not existing in table "stakeholder".
The first 2 inserts are fine, I can see them in the databases:
stakeholder:
pk_stakeholder | ...
----------------------
1 | ...
address:
pk_address | ...
--------------------
1 | ...
What am I doing wrong? I must admit that I am rather new to PostgreSQL (using 8.4) but I'm not even sure if that is an issue of PG at all, maybe I'm just lacking some basic database design understandings ...
Either way, by now I tried pretty much everything I could think of, I also tried to make the FK deferrable as in PostgreSQL : Transaction and foreign key problem but somehow that doesn't work either.
You can work around it using additional table individual_pks (individual_pk integer primary key) with all primary keys from both parent and child, which will be maintained using triggers (very simple — insert to individual_pks on insert, delete from it on delete, update it on update, if it changes individual_pk).
Then you point foreign keys to this additional table instead of a child. There'll be some small performance hit, but only when adding/deleting rows.
Or forget inheritance and do it the old way - simply one table with some nullable columns.
Your analysis is exactly right: It's because of the inheritance. When checking the foreign key, child tables are not considered.
In general, inheritance and foreign keys don't mix well in PostgreSQL. A major problem is that you can't have unique constraints across tables.
Reference