postgresql 10 altering serial column error 42p01 - postgresql

I am facing an issue when correcting an existing table to use serial column on the primary key. In order to simulate the issue I created a new table:
CREATE TABLE markets."TestSequence" (
"Id" integer NOT NULL,
"Name" text COLLATE pg_catalog."default",
CONSTRAINT "PK_TestSequence" PRIMARY KEY ("Id")
);
Then I ran the query that is causing problem:
ALTER TABLE markets."TestSequence" ALTER COLUMN "Id" TYPE integer;
ALTER TABLE markets."TestSequence" ALTER COLUMN "Id" SET NOT NULL;
CREATE SEQUENCE "TestSequence_Id_seq" AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE NO CYCLE;
ALTER TABLE markets."TestSequence" ALTER COLUMN "Id" SET DEFAULT (nextval('"TestSequence_Id_seq"'));
ALTER SEQUENCE "TestSequence_Id_seq" OWNED BY "TestSequence"."Id";
I get the following error:
ERROR: relation "TestSequence" does not exist
SQL state: 42P01
According to the doc OWNED BY does not take any schema prefix. So I tried to create the table without schema and it works fine.
CREATE TABLE "TestSequence" (
"Id" integer NOT NULL,
"Name" text COLLATE pg_catalog."default",
CONSTRAINT "PK_TestSequence" PRIMARY KEY ("Id")
);
and run the corresponding alter queries:
ALTER TABLE "TestSequence" ALTER COLUMN "Id" TYPE integer;
ALTER TABLE "TestSequence" ALTER COLUMN "Id" SET NOT NULL;
CREATE SEQUENCE "TestSequence_Id_seq" AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE NO CYCLE;
ALTER TABLE "TestSequence" ALTER COLUMN "Id" SET DEFAULT (nextval('"TestSequence_Id_seq"'));
ALTER SEQUENCE "TestSequence_Id_seq" OWNED BY "TestSequence"."Id";
How can I make this work for relations with schema?

The doc you have linked says, for owned by
The specified table must have the same owner and be in the same schema
as the sequence.
You haven't specified a schema for the sequence, so it is created in public by default, which is not the same as the table schema.
Try creating the sequence as
CREATE SEQUENCE markets."TestSequence_Id_seq" AS integer ...
That being said, nothing prevents you from specifying the schema of both the sequence and the table
ALTER SEQUENCE markets."TestSequence_Id_seq" OWNED BY markets."TestSequence"."Id";

Related

Cannot refer to table in public schema by different schema

I have the following example :
CREATE TABLE dt_totals (
dt_total date NOT NULL,
geo varchar(2) not null,
impressions integer DEFAULT 0 NOT NULL,
sales integer DEFAULT 0 NOT NULL
)
PARTITION BY RANGE (dt_total);
CREATE TABLE dt_totals_201801
PARTITION OF dt_totals
FOR VALUES FROM ('2018-01-01') TO ('2018-01-31')
PARTITION BY LIST (geo);
CREATE TABLE dt_totals_UK_201801 PARTITION OF dt_totals_201801 FOR VALUES IN ('UK');
CREATE TABLE dt_totals_US_201801 PARTITION OF dt_totals_201801 FOR VALUES IN ('US');
CREATE TABLE dt_totals_AU_201801 PARTITION OF dt_totals_201801 FOR VALUES IN ('AU');
in my environment generate a schema called level_part;
CREATE SCHEMA IF NOT EXISTS level_part
AUTHORIZATION postgres;
So far so good, I generate the main partitioned table :
CREATE TABLE IF NOT EXISTS level_part.dt_totals
(
dt_total date NOT NULL,
geo character varying(2) COLLATE pg_catalog."default" NOT NULL,
impressions integer NOT NULL DEFAULT 0,
sales integer NOT NULL DEFAULT 0
) PARTITION BY RANGE (dt_total);
ALTER TABLE IF EXISTS level_part.dt_totals
OWNER to postgres;
-- Partitions SQL
CREATE TABLE public.dt_totals_201801 PARTITION OF level_part.dt_totals
FOR VALUES FROM ('2018-01-01') TO ('2018-01-31')
PARTITION BY LIST (geo);
ALTER TABLE IF EXISTS public.dt_totals_201801
OWNER to postgres;
Questions
Why does it point to the public schema
is it a pgadmin error ?
and when I try to generate a partition as follows :
CREATE TABLE dt_totals_AU_201801 PARTITION OF level_part.dt_totals_201801 FOR VALUES IN ('AU');
I get an error :
ERROR: relation "level_part.dt_totals_201801" does not exist
SQL state: 42P01
but if I change the schema to public, I am able to refer to the table:
CREATE TABLE dt_totals_AU_201801 PARTITION OF public.dt_totals_201801 FOR VALUES IN ('AU');
Why can I only refer to the table in the public schema?
When you first create the table, you don't specify a schema, so postgres places the table in the public schema.
"...Tables without [specified] schema name. [...] By default such tables (and other objects) are automatically put into a schema named "public"
More: 5.7.2. The Public Schema

How to reference hypertables properly using foreign key constraints in PostgreSQL?

#Error description:
It's possible to create a table that has a foreign key into a hypertable provided the foreign key is defined when the table is created
#To Reproduce, there are next tables:
CREATE TABLE ids (
measurement_id int DEFAULT 0,
description text DEFAULT 0,
m_id bigserial NOT NULL,
service_id int DEFAULT NULL,
time bigint NOT NULL DEFAULT cast((EXTRACT(EPOCH FROM now() AT TIME ZONE 'UTC') * 1000) as bigint),
user_id int DEFAULT NULL,
end_time DOUBLE PRECISION DEFAULT 0,
start_time int NOT NULL DEFAULT 0
);
CREATE INDEX ON ids (time DESC, user_id);
CREATE INDEX ON ids (time DESC, service_id);
SELECT create_hypertable('ids', 'start_time', chunk_time_interval => 604800016);
---------
CREATE TABLE IF NOT EXISTS metrics (
id bigserial NOT NULL,
duration real DEFAULT NULL,
metric integer DEFAULT 0,
m_id bigint NOT NULL,
time bigint NOT NULL DEFAULT 0
);
ALTER TABLE metrics ADD PRIMARY KEY (time, m_id);
CREATE INDEX ON metrics (time DESC);
CREATE INDEX ON metrics (time DESC, measurement );
CREATE INDEX ON metrics (time DESC, m_id );
grant all privileges on ids, metrics to your_db_user;
SELECT create_hypertable('metrics', 'time' , chunk_time_interval => 604800016);
SELECT table_catalog, table_schema, table_name, privilege_type FROM information_schema.table_privileges WHERE grantee = 'your_db_user';
---------
DROP TABLE IF EXISTS resource;
CREATE TABLE resource(
id int NOT NULL,
cpu text DEFAULT 0,
storing text DEFAULT 0,
memory text DEFAULT 0
);
ALTER TABLE resource ADD PRIMARY KEY (id);
CREATE SEQUENCE resource_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE resource_id_seq
OWNER TO your_db_user;
ALTER TABLE resource ALTER COLUMN id SET DEFAULT nextval('resource_id_seq'::regclass);
---------
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
DROP TABLE IF EXISTS ns;
CREATE TABLE ns(
id bigint NOT NULL,
uuid uuid NOT NULL DEFAULT uuid_generate_v4 (),
availability double precision,
faultTolerance boolean,
activated boolean,
UNIQUE (id, uuid),
PRIMARY KEY(id),
CONSTRAINT fk_resource
FOREIGN KEY(id)
REFERENCES resource(id)
ON DELETE CASCADE
);
CREATE SEQUENCE ns_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE ns_id_seq
OWNER TO your_db_user;
ALTER TABLE ns ALTER COLUMN id SET DEFAULT nextval('ns_id_seq'::regclass);
---------
DROP TABLE IF EXISTS authentication;
CREATE TABLE authentication(
id integer NOT NULL,
username character varying(255) NOT NULL,
password character varying(255) NOT NULL,
host character varying(255) NOT NULL,
port character varying(10) NOT NULL,
PRIMARY KEY(id)
);
CREATE SEQUENCE auth_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE auth_id_seq
OWNER TO your_db_user;
ALTER TABLE authentication ALTER COLUMN id SET DEFAULT nextval('auth_id_seq'::regclass);
---------
DROP TABLE IF EXISTS job;
CREATE TABLE job(
id int NOT NULL,
interval integer NOT NULL,
auth_id integer REFERENCES authentication (id),
ns_id integer REFERENCES ns (id),
UNIQUE (auth_id, ns_id),
PRIMARY KEY(id)
);
ALTER TABLE job
ADD CONSTRAINT fk_auth_id
FOREIGN KEY (id) REFERENCES authentication (id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE job
ADD CONSTRAINT fk_ns_id
FOREIGN KEY (id) REFERENCES ns (id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED;
CREATE SEQUENCE job_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE job_id_seq
OWNER TO your_db_user;
ALTER TABLE job ALTER COLUMN id SET DEFAULT nextval('job_id_seq'::regclass);
---------
DROP TABLE IF EXISTS job_metric;
CREATE TABLE job_metric (
id int NOT NULL,
j_id int NOT NULL REFERENCES job (id),
mj_id bigint NOT NULL,
jm_time bigint NOT NULL
);
CREATE INDEX ON job_metric (jm_time DESC);
CREATE INDEX ON job_metric (jm_time DESC, id);
CREATE INDEX ON job_metric (jm_time DESC, mj_id);
ALTER TABLE job_metric ADD PRIMARY KEY (jm_time, id);
grant all privileges on job_metric to your_db_user;
SELECT create_hypertable('job_metric', 'jm_time' , chunk_time_interval => 604800016);
CREATE SEQUENCE mjob_metric_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE mjob_metric_id_seq
OWNER TO your_db_user;
ALTER TABLE job_metric ALTER COLUMN id SET DEFAULT nextval('mjob_metric_id_seq'::regclass);
---------
After creating the tables, I have used the solution proposed by #Laurenz in a database with PostgreSQL 12.6 using the extension of timescaledb 1.7.5 as follows:
#To fill the table with the appropriate values:
UPDATE job_metric AS jm_point
SET jm_time = qm.time
FROM metrics AS qm
WHERE qm.m_id = jm_point.mj_id;
#Then set it NOT NULL:
ALTER TABLE job_metric ALTER jm_time SET NOT NULL;
#To define your foreign key:
ALTER TABLE job_metric
ADD FOREIGN KEY (mj_id, jm_time)
REFERENCES metrics (time, m_id) MATCH FULL;
#Response of the last reference table to enable foreign key: Query returned successfully in 40 msec.
Expected behavior:
The idea is to use the table job_metric in an even many-to-many relationship to access the information of job and metrics tables.
Actual behavior and error:
Tables are created and FKs were created but cannot be used when data is inserted at job_metric as is detailed in the following:
INSERT INTO job_metric (j_id, mj_id, jm_time)
VALUES(13, 185063, 1621957192266);
ERROR: foreign keys to hypertables are not supported CONTEXT: SQL
statement " ALTER TABLE _timescaledb_internal._hyper_5_5_chunk ADD
CONSTRAINT "5_13_job_metric_j_id_mj_id_jm_time_fkey" FOREIGN KEY
(j_id, mj_id, jm_time) REFERENCES qmetrics("time", m_id) MATCH FULL "
PL/pgSQL function
_timescaledb_internal.chunk_constraint_add_table_constraint(_timescaledb_catalog.chunk_constraint)
line 42 at EXECUTE SQL state: 0A000
***According to https://docs.timescale.com/timescaledb/latest/overview/limitations/##distributed-hypertable-limitations, it looks like the above error is part of the hypertable limitations:
Foreign key constraints referencing a hypertable are not supported.
#Request:
Given the above information and errors, does anyone know any solution at the DB level to establish the relationships (many-to-many or one-to-many) using timescaledb extension and mainly hypertables?
Actually, I have obtained similar of above error when I had attempted to create many-to-many relation among the tables metrics and job_metric using the Django Rest Framework:
class Job_Metrics(models.Model):
job = models.OneToOneField(Job, on_delete=models.CASCADE)
metrics = models.ManyToManyField(Metrics)
time = models.IntegerField(default=0)
Running the application metrics pointing out directly metrics_db:
$ python3 manage.py migrate metrics --database=metrics_db
Operations to perform: Apply all migrations: metrics Running migrations: Applying
metrics.0002_job...Traceback (most recent call last): File
"/var/myproject/myprojectenv/lib/python3.8/site-packages/django/db/backends/utils.py",
line 84, in _execute return self.cursor.execute(sql, params)
psycopg2.errors.FeatureNotSupported: foreign keys to hypertables are
not supported
If someone knows a solution or has an idea to deal with the above error at the REST API level, please could you share your idea with the aim to access data associated tables (metrics and jobs) and modify them together when is required to delete e.g., a job_metric. So far, using hypertables amendments of timescaledb extension seems to be not a viable solution.

How to use psql to restore database with relations?

I am trying to restore database using psql. But it seems like psql always fail when it encounter CONSTRAINT. After I look into the dump. I found out that the child table, the table that hold FOREIGN KEY, is created before the parent table.
Here is the snippet...
DROP TABLE IF EXISTS "answer";
DROP SEQUENCE IF EXISTS answer_id_seq;
CREATE SEQUENCE answer_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 71 CACHE 1;
CREATE TABLE "public"."answer" (
"id" integer DEFAULT nextval('answer_id_seq') NOT NULL,
"text" character varying NOT NULL,
"weight" double precision NOT NULL,
"questionId" integer NOT NULL,
"baseCreated" timestamp DEFAULT now() NOT NULL,
"baseUpdated" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "PK_9232db17b63fb1e94f97e5c224f" PRIMARY KEY ("id"),
CONSTRAINT "FK_a4013f10cd6924793fbd5f0d637" FOREIGN KEY ("questionId") REFERENCES question(id) ON DELETE CASCADE NOT DEFERRABLE
) WITH (oids = false);
psql command.
psql -h 0.0.0.0 -p 5432 -U foobar -1 foobar < foobar.sql
And the error.
NOTICE: table "answer" does not exist, skipping
DROP TABLE
NOTICE: sequence "answer_id_seq" does not exist, skipping
DROP SEQUENCE
CREATE SEQUENCE
ERROR: relation "question" does not exist
ERROR: relation "answer" does not exist
ERROR: relation "answer" does not exist
LINE 1: INSERT INTO "answer" ("id", "text", "weight", "questionId", ...

PGSQL Insert into A get ID to Insert into B

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.

How to insert value into a column with a default value? [PostgreSQL 9.1]

I have such table:
CREATE TABLE employee (
id INTEGER DEFAULT NEXTVAL('ids'::regclass) NOT NULL,
name CHARACTER VARYING NOT NULL,
employer INTEGER DEFAULT (-1)
);
And I want to insert sth into this table (I want to leave employer as default, -1):
INSERT INTO employee (name, id) VALUES('Doe', 2);
but my PostgreSQL 9.1 is complaining:
ERROR: insert or update on table "employee" violates foreign key constraint "FK_employer"
DETAIL: Key (employer)=(-1) is not present in table "employer".
I know that theres no employer with id = -1 but still, I want it that way. I want to set employer as -1 for this emplyee. Is it possible with postgreSQL?
Make the default null. Is it good?
employer INTEGER DEFAULT null