Actually my question is basically the same as here but I need to insert values from a nested query into an existing table and I'am not that familiar with sql as to know how to incorporate the setval part into my query:
insert into table_a
select *
from table_b
where val_1 IN (select "val_1" from table_c where "val_2" is null)
returns
ERROR: duplicate key value violates unique constraint "table_a_pkey"
DETAIL: Key (qid)=(470971) already exists.
Now I know I could do a workaround with drop column and autgenerate as described here but there must be a more elegant way. I am using Postgresql/Postgis 2.4 btw.
It he primary key is auto-generated, don't insert the PK column:
insert into table_a (some_column, other_column, third_column)
select some_column, other_column, third_column
from table_b
where val_1 IN (select "val_1" from table_c where "val_2" is null)
(I had to guess the column names as you did not provide the real ones)
Related
I have a table 'new_table' with sequence id as primary key.
how can I insert new records to it with data from other table. I tried:
insert into new_table (
(select (select NEXTVAL('my_sequence')),a,b,c from old_table)
);
but got
duplicate key value violates unique constraint DETAIL: Key (id)=(...)
already exists.
just list columns skipping the one with sequence, smth like:
insert into new_table (a,b,c) select a,b,c from old_table;
If default value is set to get nextval, you don't have to do it manually.
check if your sequence is not behind the max(id) value. smth like:
select max(id) from new_table
if it is, restart sequence with new cellar, smth like:
alter sequence my_sequence restart with 1999; or what your maximum is
I am trying to do what is described in this solution and also here. That means I would like to copy rows with many columns while changing only a few values. So my query looks like this:
CREATE TEMPORARY TABLE temp_table AS
SELECT * FROM original_table WHERE <conditions>;
UPDATE temp_table
SET <auto_inc_field>=NULL,
<fieldx>=<valuex>,
<fieldy>=<valuey>;
INSERT INTO original_table SELECT * FROM temporary_table;
However, the <auto_inc_field>=NULL part is not working for me, respectively my PostgreSQL 9.4 database:
Exception: null value in column "auto_inc_field" violates not-null constraint
The <auto_inc_field> column is defined as BIGINT, SERIAL, and has a primary key constraint.
What do I need to pass, if NULL is not working? Is there an alternative method?
I understand that the primary key is a serial. List all columns but the primary key in the insert command. List the correspondent columns and values in the select command:
insert into original_table (col_1, col_2, col_3)
select col_1, value_2, value_2
from original_table
where the_conditions;
I have a table that has one column with unordered value. I want to order this column descending and add a column to record its order. My SQL code is:
select *
into newtable
from oldtable
order by column_name desc;
alter table newtable add column id serial;
Would this implement my goal? I know that rows in PostgreSQL have no fixed order. So I am not sure about this.
Rather than (ab)using a SERIAL via ALTER TABLE, generate it at insert-time.
CREATE TABLE newtable (id serial unique not null, LIKE oldtable INCLUDING ALL);
INSERT INTO newtable
SELECT nextval('newtable_id_seq'), *
FROM oldtable
ORDER BY column_name desc;
This avoids a table rewrite, and unlike your prior approach, is guaranteed to produce the correct ordering.
(If you want it to be the PK, and the prior table had no PK, change unique not null to primary key. If the prior table had a PK you'll need to use a LIKE variant that excludes constraints).
You can first create a new table, sorted based on the column you want to use:
CREATE TABLE newtable AS
SELECT * FROM oldtable
ORDER BY column_name desc;
Afterwards, since you want to order from the largest to the smallest, you can add a new column to your table:
ALTER TABLE newtable ADD COLUMN id serial unique;
I have a column in db which has 5 columns but no primary key.
One of the columns is named myTable_id and is integer.
I want to check if the table has a primary key column. If it doesn't, then make myTable_id a primary key column and make it identity column. Is there a way to do this?
I tried with this:
ALTER TABLE Persons
DROP CONSTRAINT pk_PersonID
ALTER TABLE Persons
ADD PRIMARY KEY (P_Id)
and I get syntax error in Management studio.
This checks if primary key exists, if not it is created
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = 'Persons'
AND TABLE_SCHEMA ='dbo')
BEGIN
ALTER TABLE Persons ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id)
END
ELSE
BEGIN
-- Key exists
END
fiddle: http://sqlfiddle.com/#!6/e165d/2
ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id)
An IDENTITY constraint can't be added to an existing column, so how you add this needs to be your initial thought. There are two options:
Create a new table including a primary key with identity and drop the existing table
Create a new primary key column with identity and drop the existing 'P_ID' column
There is a third way, which is a better approach for very large tables via the ALTER TABLE...SWITCH statement. See Adding an IDENTITY to an existing column for an example of each. In answer to this question, if the table isn't too large, I recommend running the following:
-- Check that the table/column exist and no primary key is already on the table.
IF COL_LENGTH('PERSONS','P_ID') IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = 'PERSONS')
-- Add table schema to the WHERE clause above e.g. AND TABLE_SCHEMA ='dbo'
BEGIN
ALTER TABLE PERSONS
ADD P_ID_new int IDENTITY(1, 1)
GO
ALTER TABLE PERSONS
DROP COLUMN P_ID
GO
EXEC sp_rename 'PERSONS.P_ID_new', 'P_ID', 'Column'
GO
ALTER TABLE PERSONS
ADD CONSTRAINT PK_P_ID PRIMARY KEY CLUSTERED (P_ID)
GO
END
Notes:
By explicitly using the CONSTRAINT keyword the primary key constraint is given a particular name rather than depending on SQL Server to auto-assign a name.
Only include CLUSTERED on the PRIMARY KEY if the balance of searches for a particular P_ID and the amount of writing outweighs the benefits of clustering the table by some other index. See Create SQL IDENTITY as PRIMARY KEY.
You can check if primary key exists or not using OBJECTPROPERTY Transact SQL, use 'TableHasPrimaryKey' for the second arguments.
DECLARE #ISHASPRIMARYKEY INT;
SELECT #ISHASPRIMARYKEY = OBJECTPROPERTY(OBJECT_ID('PERSONS'), 'TABLEHASPRIMARYKEY');
IF #ISHASPRIMARYKEY IS NULL
BEGIN
-- generate identity column
ALTER TABLE PERSONS
DROP COLUMN P_ID;
ALTER TABLE PERSONS
ADD P_ID INT IDENTITY(1,1);
-- add primary key
ALTER TABLE PERSONS
ADD CONSTRAINT PK_PERSONID PRIMARY KEY (P_ID);
END;
I don't think you can do that. For making a column into an identity column I think you have to drop the table entirely.
I've created some tables in postgres, added a foreign key from one table to another and set ON DELETE to CASCADE. Strangely enough, I have some fields that appear to be violating this constraint.
Is this normal behaviour? And if so, is there a way to get the behaviour I want (no violations possible)?
Edit:
I orginaly created the foreign key as part of CREATE TABLE, just using
... REFERENCES product (id) ON UPDATE CASCADE ON DELETE CASCADE
The current code pgAdmin3 gives is
ALTER TABLE cultivar
ADD CONSTRAINT cultivar_id_fkey FOREIGN KEY (id)
REFERENCES product (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
Edit 2:
To Clarify, I have a sneaking suspicion that the constraints are only checked when updates/inserts happen but are then never looked at again. Unfortunately I don't know enough about postgres to find out if this is true or how fields could end up in the database without those checks being run.
If this is the case, is there some way to check all the foreign keys and fix those problems?
Edit 3:
A constraint violation can be caused by a faulty trigger, see below
I tried to create a simple example that shows foreign key constraint being enforced. With this example I prove I'm not allowed to enter data that violates the fk and I prove that if the fk is not in place during insert, and I enable the fk, the fk constraint throws an error telling me data violates the fk. So I'm not seeing how you have data in the table that violates a fk that is in place. I'm on 9.0, but this should not be different on 8.3. If you can show a working example that proves your issue that might help.
--CREATE TABLES--
CREATE TABLE parent
(
parent_id integer NOT NULL,
first_name character varying(50) NOT NULL,
CONSTRAINT pk_parent PRIMARY KEY (parent_id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE parent OWNER TO postgres;
CREATE TABLE child
(
child_id integer NOT NULL,
parent_id integer NOT NULL,
first_name character varying(50) NOT NULL,
CONSTRAINT pk_child PRIMARY KEY (child_id),
CONSTRAINT fk1_child FOREIGN KEY (parent_id)
REFERENCES parent (parent_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
ALTER TABLE child OWNER TO postgres;
--CREATE TABLES--
--INSERT TEST DATA--
INSERT INTO parent(parent_id,first_name)
SELECT 1,'Daddy'
UNION
SELECT 2,'Mommy';
INSERT INTO child(child_id,parent_id,first_name)
SELECT 1,1,'Billy'
UNION
SELECT 2,1,'Jenny'
UNION
SELECT 3,1,'Kimmy'
UNION
SELECT 4,2,'Billy'
UNION
SELECT 5,2,'Jenny'
UNION
SELECT 6,2,'Kimmy';
--INSERT TEST DATA--
--SHOW THE DATA WE HAVE--
select parent.first_name,
child.first_name
from parent
inner join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
--SHOW THE DATA WE HAVE--
--DELETE PARENT WHO HAS CHILDREN--
BEGIN TRANSACTION;
delete from parent
where parent_id = 1;
--Check to see if any children that were linked to Daddy are still there?
--None there so the cascade delete worked.
select parent.first_name,
child.first_name
from parent
right outer join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
ROLLBACK TRANSACTION;
--TRY ALLOW NO REFERENTIAL DATA IN--
BEGIN TRANSACTION;
--Get rid of fk constraint so we can insert red headed step child
ALTER TABLE child DROP CONSTRAINT fk1_child;
INSERT INTO child(child_id,parent_id,first_name)
SELECT 7,99999,'Red Headed Step Child';
select parent.first_name,
child.first_name
from parent
right outer join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
--Will throw FK check violation because parent 99999 doesn't exist in parent table
ALTER TABLE child
ADD CONSTRAINT fk1_child FOREIGN KEY (parent_id)
REFERENCES parent (parent_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
ROLLBACK TRANSACTION;
--TRY ALLOW NO REFERENTIAL DATA IN--
--DROP TABLE parent;
--DROP TABLE child;
Everything I've read so far seems to suggest that constraints are only checked when the data is inserted. (Or when the constraint is created) For example the manual on set constraints.
This makes sense and - if the database works properly - should be good enough. I'm still curious how I managed to circumvent this or if I just read the situation wrong and there was never a real constraint violation to begin with.
Either way, case closed :-/
------- UPDATE --------
There was definitely a constraint violation, caused by a faulty trigger. Here's a script to replicate:
-- Create master table
CREATE TABLE product
(
id INT NOT NULL PRIMARY KEY
);
-- Create second table, referencing the first
CREATE TABLE example
(
id int PRIMARY KEY REFERENCES product (id) ON DELETE CASCADE
);
-- Create a (broken) trigger function
--CREATE LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION delete_product()
RETURNS trigger AS
$BODY$
BEGIN
DELETE FROM product WHERE product.id = OLD.id;
-- This is an error!
RETURN null;
END;
$BODY$
LANGUAGE plpgsql;
-- Add it to the second table
CREATE TRIGGER example_delete
BEFORE DELETE
ON example
FOR EACH ROW
EXECUTE PROCEDURE delete_product();
-- Now lets add a row
INSERT INTO product (id) VALUES (1);
INSERT INTO example (id) VALUES (1);
-- And now lets delete the row
DELETE FROM example WHERE id = 1;
/*
Now if everything is working, this should return two columns:
(pid,eid)=(1,1). However, it returns only the example id, so
(pid,eid)=(0,1). This means the foreign key constraint on the
example table is violated.
*/
SELECT product.id AS pid, example.id AS eid FROM product FULL JOIN example ON product.id = example.id;