How to get primary key sequence in Postgres? - postgresql

I have following table:
-- DDL generated by Postico 1.5.10
-- Not all database features are supported. Do not use for backup.
-- Table Definition ----------------------------------------------
CREATE TABLE "Ticket" (
id bigint PRIMARY KEY,
"paymentId" text NOT NULL,
"transactionId" text,
"dateCreated" timestamp without time zone NOT NULL,
"dateValidated" timestamp without time zone,
"sellerPaymentId" text NOT NULL,
"sellerPaymentProvider" text NOT NULL,
"userId" bigint NOT NULL,
"userIdFb" text NOT NULL,
"userName" text NOT NULL,
"eventDescription" text NOT NULL,
"eventTimeId" text,
"eventId" text NOT NULL,
"eventName" text NOT NULL,
"startTime" timestamp without time zone,
"endTime" timestamp without time zone,
quantity bigint,
"unitPrice" text,
seats jsonb[],
location text NOT NULL,
link text,
"eventTimesSelected" jsonb,
"otherListsSelected" jsonb,
"transactionIdBarion1" text,
"transactionIdBarion2" text
);
-- Indices -------------------------------------------------------
CREATE UNIQUE INDEX "pk:Ticket.id" ON "Ticket"(id int8_ops);
When inserting a new row, got this error:
[ ERROR ] PostgreSQLError.server.error._bt_check_unique: POST /startPayment duplicate key value violates unique constraint "pk:Ticket.id" (ErrorMiddleware.swift:26)
[ DEBUG ] Possible causes for PostgreSQLError.server.error._bt_check_unique: Key (id)=(1) already exists. (ErrorMiddleware.swift:26)
How the heck I can reset the primary key sequence? There are many answers on internet, but what is the name of my sequence? :) I do not see any 'name' in my DDL.
I tried fetch sequence name like this:
select currval(pg_get_serial_sequence("Ticket", "id"));
no luck:
ERROR: column "Ticket" does not exist
LINE 1: select currval(pg_get_serial_sequence("Ticket", "id"));

pg_get_serial_sequence() expects string values, not identifiers. Your problems stem from the fact that you used those dreaded quoted identifiers when creating the table which is strongly discouraged.
You need to pass the double quotes inside single quotes:
select currval(pg_get_serial_sequence('"Ticket"', '"id"'));
You should reconsider the usage of quoted identifiers to avoid problems like that in the future.
How the heck I can reset the primary key sequence
How to reset postgres' primary key sequence when it falls out of sync?
How to bulk update sequence ID postgreSQL for all tables

Related

UPSERT: duplicate key value violates unique constraint

I want to increment search counter when user searches a word.
create table public."SearchLog" (
id integer primary key not null default nextval('"SearchLog_id_seq"'::regclass),
search character varying(192),
replacement character varying(192),
qty integer,
visible boolean,
created_at timestamp(3) without time zone default CURRENT_TIMESTAMP(3),
updated_at timestamp(3) without time zone default CURRENT_TIMESTAMP(3)
);
when i run the code
insert into "SearchLog" (search)
values ('test')
on conflict(search) do update set qty = excluded.qty + 1,
updated_at = current_timestamp(3);
i get this error:
[23505] ERROR: duplicate key value violates unique constraint "SearchLog_pkey"
why "on coflict" doesn't trigger? how it can violates pkey if i even didn't provided it?

Postgres SQL Table Partitioning by Range Timestamp not Unique key Collision

I have an issue when trying to modify and existing PostgreSQL (version 13.3) table to support partitioning it gets stuck when inserting the new data from the old table because the inserted timestamp in some cases may not be unique, so it fails on execution.
The partition forces me to create the primary to be the range (timestamp) value. You can see the new table definition below:
CREATE TABLE "UserFavorites_master" (
"Id" int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"UserId" int4 NOT NULL,
"CardId" int4 NOT NULL,
"CreationDate" timestamp NOT NULL,
CONSTRAINT "PK_UserFavorites_CreationDate" PRIMARY KEY ("CreationDate")
) partition by range ("CreationDate");
The original table didn't have a constraint on timestamp to either be unique or a primary key nor would we particularly want that but that seems to be a requirement of partitioning. Looking for alternatives or good ideas to solve the issue.
You can see the full code below:
alter table "UserFavorites" rename to "UserFavorites_old";
CREATE TABLE "UserFavorites_master" (
"Id" int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"UserId" int4 NOT NULL,
"CardId" int4 NOT NULL,
"CreationDate" timestamp NOT NULL,
CONSTRAINT "PK_UserFavorites_CreationDate" PRIMARY KEY ("CreationDate")
) partition by range ("CreationDate");
-- Frome Reference: https://stackoverflow.com/a/53600145/1190540
create or replace function createPartitionIfNotExists(forDate timestamp) returns void
as $body$
declare yearStart date := date_trunc('year', forDate);
declare yearEndExclusive date := yearStart + interval '1 year';
declare tableName text := 'UserFavorites_Partition_' || to_char(forDate, 'YYYY');
begin
if to_regclass(tableName) is null then
execute format('create table %I partition of "UserFavorites_master" for values from (%L) to (%L)', tableName, yearStart, yearEndExclusive);
-- Unfortunatelly Postgres forces us to define index for each table individually:
--execute format('create unique index on %I (%I)', tableName, 'UserId'::text);
end if;
end;
$body$ language plpgsql;
do
$$
declare rec record;
begin
loop
for rec in 2015..2030 loop
-- ... and create a partition for them
perform createPartitionIfNotExists(to_date(rec::varchar,'yyyy'));
end loop;
end
$$;
create or replace view "UserFavorites" as select * from "UserFavorites_master";
insert into "UserFavorites" ("Id", "UserId", "CardId", "CreationDate") select * from "UserFavorites_old";
It fails on the Last line with the following error:
SQL Error [23505]: ERROR: duplicate key value violates unique constraint "UserFavorites_Partition_2020_pkey"
Detail: Key ("CreationDate")=(2020-11-02 09:38:54.997) already exists.
ERROR: duplicate key value violates unique constraint "UserFavorites_Partition_2020_pkey"
Detail: Key ("CreationDate")=(2020-11-02 09:38:54.997) already exists.
ERROR: duplicate key value violates unique constraint "UserFavorites_Partition_2020_pkey"
Detail: Key ("CreationDate")=(2020-11-02 09:38:54.997) already exists.
No, partitioning doesn't force you to create a primary key. Just omit that line, and your example should work.
However, you definitely always should have a primary key on your tables. Otherwise, you can end up with identical rows, which is a major headache in a relational database. You might have to clean up your data.
#Laurenz Albe is correct, it seems I also have the ability to specify multiple keys though it may affect performance as referenced here Multiple Keys Performance, even indexing the creation date of the partition seemed to make the performance worse.
You can see a reference to multiple keys below, you mileage may vary.
CREATE TABLE "UserFavorites_master" (
"Id" int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"UserId" int4 NOT NULL,
"CardId" int4 NOT NULL,
"CreationDate" timestamp NOT NULL,
CONSTRAINT "PK_UserFavorites" PRIMARY KEY ("Id", "CreationDate")
) partition by range ("CreationDate");

Why regenerated Postgres table raise error in Vapor?

A table in production environment was created like this:
-- DDL generated by Postico 1.5.10
-- Not all database features are supported. Do not use for backup.
-- Table Definition ----------------------------------------------
CREATE TABLE "TempUser" (
id bigint PRIMARY KEY,
"Uuid" text NOT NULL,
"dateCreated" timestamp without time zone NOT NULL,
"lastRequestDate" timestamp without time zone NOT NULL,
"lastRequestLocation" text,
"numOfRequest" bigint NOT NULL,
comment text NOT NULL,
"lastRequestDescription" text NOT NULL,
"bookedSeats" text NOT NULL,
"bookUntil" timestamp without time zone,
"lastEventVisited" text
);
-- Indices -------------------------------------------------------
CREATE UNIQUE INDEX "pk:TempUser.id" ON "TempUser"(id int8_ops);
Why I remove table in dev environment and create like this in Postgres console, I got following error after try writing programmatically:
[ ERROR ] PostgreSQLError.server.error.ExecConstraints: POST /registerTempUser null value in column "id" violates not-null constraint (ErrorMiddleware.swift:26)
[ DEBUG ] Possible causes for PostgreSQLError.server.error.ExecConstraints: Failing row contains (null, 015574220836500, 2020-07-09 19:42:36.803846, 2020-07-09 19:42:36.803846, null, 1, , POST /registerTempUser HTTP/1.1
Host: localhost:8080
Content-Typ..., [], null, null). (ErrorMiddleware.swift:26)
Why, what is wrong?
Tried set sequence thing:
select setval(pg_get_serial_sequence('"TempUser"', 'id'), 1);
select currval(pg_get_serial_sequence('"TempUser"', 'id'));
nothing changed.

PostgreSQL foreign keys multiple keys on single table

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?

Update ID column from another table while using copy from csv

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);