I have a postgres table creating with the following SQL:
CREATE TABLE mytable (
mytable_id BIGSERIAL NOT NULL,
mytable_char VARCHAR(8) NOT NULL
)
This creates the table as well as an implicit mytable_mytable_id_seq sequence.
Now, after creating 1.000.000 records, I want to split this table into partitioned tables (using inheritance). Because I link refer to the main table from other tables, I want to keep using the IDs from the original table in the new child tables and keep using the sequence.
However, if I do DROP TABLE mytable it also deletes the sequence. How can I keep the sequence when dropping the table?
You need to first remove the association between the column and the sequence:
alter sequence mytable_mytable_id_seq owned by none;
If you now drop the table, the sequence will not be dropped.
Details are in the manual: http://www.postgresql.org/docs/current/static/sql-altersequence.html
An alternative is to create a new sequence and set that to the value of the existing sequence:
create sequence part_seq;
select setval('part_seq', (select nextval('mytable_mytable_id_seq'), false);
Related
I am trying to ALTER a table to use partitions LIST in postgres 11. I have been trying for hours but i keep getting errors.
I have a huge table, clients, with ( client_id, customer_id, value).
I have already created a new empty table, clients, by renaming the old table to clients_old and then created the new table with: CREATE TABLE clients( like clients_old including all).
And from here I am stuck when trying to add the LIST partition.
I have tried to:
ALTER TABLE Clients attach PARTITION BY LIST (client_id) --> fail;
ALTER TABLE Clients attach PARTITION LIST (client_id) --> fail;
ALTER TABLE Clients ADD PARTITION LIST (client_id) --> fail;
What syntax should I use to alter the table to use partitions?
Quote from the manual
It is not possible to turn a regular table into a partitioned table or vice versa
So, you can not change an existing non-partitioned table to a partitioned table.
You need to create a new table (with a different name) that is partitioned, create all necessary partitions and then copy the data from the old table to the new, partitioned table.
Something like:
create table clients_partitioned
(
.... all columns ...
)
PARTITION BY LIST (client_id);
Then create the partitions:
create table clients_1
partition of clients_partioned
for values in (1,2,3);
create table clients_1
partition of clients_partioned
for values in (4,5,6);
Then copy the data:
insert into clients_partitioned
select *
from clients;
Once that is done, you can drop the old table and rename the new table:
drop table clients;
alter table clients_partitioned rename to clients;
Don't forget to re-create your foreign keys and indexes.
I had to add for tag in order to add the partition:
create table clients_1
partition of clients_partioned
for values in (4,5,6);
because without for was a syntax error.
In postgresql update/insert are very slow. So often is faster create a new table with the new field/row and then replace the old table
The thing is I need an autonumeric so in this case I had to create the table first and do the insert later.
Is there a way create an autonumeric field in the select so I can use
CREATE TABLE source.road_nodes AS
SELECT serial_field, node
instead of CREATE TABLE + INSERT.
CREATE TABLE source.road_nodes (
node_id serial,
node TEXT
);
INSERT INTO source.road_nodes (node)
SELECT DISTINCT node
FROM
(
SELECT DISTINCT node_begin AS node
FROM source.vzla_rto
) as node_pool;
In a way this is possible. You can take advantage of the fact that as the PostgreSQL documentation - 8.1.4. Serial Types states:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
Creating a sequence separately and making the next value the default for the column you effectively make it a SERIAL column.
CREATE SEQUENCE road_nodes_node_id_seq;
CREATE TABLE road_nodes AS
SELECT DISTINCT ON (node) nextval('road_nodes_node_id_seq') AS node_id, node FROM vzla_rto;
ALTER TABLE road_nodes ALTER node_id SET NOT NULL, ALTER COLUMN node_id SET DEFAULT nextval('road_nodes_node_id_seq');
You could keep the sequence and just reset it to one when you would recreate the table.
I wouldn't say that this is an elegant way however and probably the easiest way is just to create the table separately.
Hello I want to delete all data in my postgresql tables, but not the table itself.
How could I do this?
Use the TRUNCATE TABLE command.
The content of the table/tables in PostgreSQL database can be deleted in several ways.
Deleting table content using sql:
Deleting content of one table:
TRUNCATE table_name;
DELETE FROM table_name;
Deleting content of all named tables:
TRUNCATE table_a, table_b, …, table_z;
Deleting content of named tables and tables that reference to them (I will explain it in more details later in this answer):
TRUNCATE table_a, table_b CASCADE;
Deleting table content using pgAdmin:
Deleting content of one table:
Right click on the table -> Truncate
Deleting content of table and tables that reference to it:
Right click on the table -> Truncate Cascaded
Difference between delete and truncate:
From the documentation:
DELETE deletes rows that satisfy the WHERE clause from the specified
table. If the WHERE clause is absent, the effect is to delete all rows
in the table.
http://www.postgresql.org/docs/9.3/static/sql-delete.html
TRUNCATE is a PostgreSQL extension that provides a faster mechanism to
remove all rows from a table. TRUNCATE quickly removes all rows from a
set of tables. It has the same effect as an unqualified DELETE on each
table, but since it does not actually scan the tables it is faster.
Furthermore, it reclaims disk space immediately, rather than requiring
a subsequent VACUUM operation. This is most useful on large tables.
http://www.postgresql.org/docs/9.1/static/sql-truncate.html
Working with table that is referenced from other table:
When you have database that has more than one table the tables have probably relationship.
As an example there are three tables:
create table customers (
customer_id int not null,
name varchar(20),
surname varchar(30),
constraint pk_customer primary key (customer_id)
);
create table orders (
order_id int not null,
number int not null,
customer_id int not null,
constraint pk_order primary key (order_id),
constraint fk_customer foreign key (customer_id) references customers(customer_id)
);
create table loyalty_cards (
card_id int not null,
card_number varchar(10) not null,
customer_id int not null,
constraint pk_card primary key (card_id),
constraint fk_customer foreign key (customer_id) references customers(customer_id)
);
And some prepared data for these tables:
insert into customers values (1, 'John', 'Smith');
insert into orders values
(10, 1000, 1),
(11, 1009, 1),
(12, 1010, 1);
insert into loyalty_cards values (100, 'A123456789', 1);
Table orders references table customers and table loyalty_cards references table customers. When you try to TRUNCATE / DELETE FROM the table that is referenced by other table/s (the other table/s has foreign key constraint to the named table) you get an error. To delete content from all three tables you have to name all these tables (the order is not important)
TRUNCATE customers, loyalty_cards, orders;
or just the table that is referenced with CASCADE key word (you can name more tables than just one)
TRUNCATE customers CASCADE;
The same applies for pgAdmin. Right click on customers table and choose Truncate Cascaded.
For small tables DELETE is often faster and needs less aggressive locking (important for concurrent load):
DELETE FROM tbl;
With no WHERE condition.
For medium or bigger tables, go with TRUNCATE, like #Greg posted:
TRUNCATE tbl;
Hard to pin down the line between "small" and "big", as that depends on many variables. You'll have to test in your installation.
I found a very easy and fast way for everyone who might use a tool like DBeaver:
You just need to select all the tables that you want to truncate (SHIFT + click or CTRL + click) then right click
And if you have foreign keys, select also CASCADE option on Settings panel. Start and that's all it takes!
I have some problems with SQL-code.
Sequences and tables creation, some data inserting in:
CREATE SEQUENCE tmp_id_places START 1;
CREATE SEQUENCE tmp_id_books START 1;
CREATE TABLE tmp_places (
id int PRIMARY KEY DEFAULT nextval('tmp_id_places'),
name text
);
CREATE TABLE tmp_cities (population int) INHERITS (tmp_places);
CREATE TABLE tmp_rivers (lenght int) INHERITS (tmp_places);
INSERT INTO tmp_cities (name, population) VALUES
('Moscow', 15),
('St. Petersburg', 9);
INSERT INTO tmp_rivers (name, lenght) VALUES
('Volga', 115),
('Angara', 319);
CREATE TABLE tmp_books (
id int PRIMARY KEY DEFAULT nextval('tmp_id_books'),
id_place int REFERENCES tmp_places(id),
title text
);
Вut this code make an error:
INSERT INTO tmp_books (title, id_place) VALUES
('Some book about Moscow', 1),
('Another book about Angara', 4);
Table tmp_books contain information about places. But I can't insert data in it, because there aren't any data in master-table tmp_places (all data in child-tables).
So can this been resolved anyway?
Take a closer look at this section in the PostrgeSQL docs. If you will insert data into the child table, then data will be found only in the child table. On the other hand, inserting into the master table makes new rows visible in all the child tables also. So you have to always work on the master tables at first hand.
I've been working with inheritance a while ago and also faced the same problem.
I ended up with the following:
INSERT a new entry into the tmp_places;
UPDATE extra fields, say, in tmp_cities with their respective values.
Back in 7.4 times I had to create a set of functions for such activities.
Now it is possible to use the RETURNING clause of INSERT statement and CTEs with UPDATE (also on SQL Fiddle):
WITH theid AS (
INSERT INTO tmp_places (name) VALUES ('Moscow') RETURNING id
)
UPDATE tmp_cities tc SET population = 15
FROM theid
WHERE tc.id = theid.id;
You should also be careful with constraints, as not all of them are inherited.
Denis,
Inheritance does not propagate in INSERT and COPY statements in Postgres.
In PostgreSQL you shouldn't create a foreign key to parent table because, as you just find out, this table acts almost as a view instead of a table (since actual data are in their respective children). For now only be solved by triggers.
You can see an example of this "type of triggers".
I would like to drop the sequence used in table and the table itself in one statement using CASCADE, but I'm getting NOTICE and table is not dropped. For example:
CREATE SEQUENCE seq1;
CREATE TABLE t1 (f1 INT NOT NULL DEFAULT nextval('seq1'));
And then when I do:
DROP SEQUENCE seq1 CASCADE;
I get following message, and the table is not dropped:
NOTICE: drop cascades to default for table t1 column f1
I'm definitely doing something wrong but these are my very first steps in PostgreSQL.
The table is never a depending object of an associated sequence and is never dropped by:
DROP SEQUENCE ... CASCADE;
Only a column DEFAULT drawing from the sequence "depends" on the sequence and is set to NULL if the sequence is deleted with CASCADE.
It's the other way round: if the sequence is owned by a table column it is dropped with:
DROP TABLE f1 CASCADE;
For a sequence to be owned by a table column you can either use the serial type, or ALTER an existing sequence:
ALTER SEQUENCE seq1 OWNED BY t1.f1;
I don't know why are you creating a sequence manually - maybe you have justification, or maybe it's due to habits working with another DBMS.
But if you don't have a special need for it, use the SERIAL pseudo-type and when you drop the table the sequence(s) behind the SERIAL column(s) will be dropped too.
You asked to drop the sequence and cascade that action. While the default can't exist without the sequence, and it is therefore dropped, the table and the column can exist without the sequence, so they remain.
With the way you've specified this, dropping the table will not drop the sequence, although you can make the sequence depend on the column with which it is used, and therefore have it drop automatically if you drop the table. You can do this by altering the owner of the sequence, or use SERIAL instead. Declaring a column to be type SERIAL automatically creates a sequence, makes it generate a default for the column, and makes that column the owner of the sequence.
drop cascade table table_name;
you can also use this... and i will also recommend you to use a serial with primary key so that you can identify a column uniquely..