Get or else insert in PostgreSQL - sql

I have a table of objects with columns for a number of properties and a column with a unique, SERIAL identifier.
for example:
CREATE TABLE person(
id SERIAL NOT NULL,
name VARCHAR(16) NOT NULL,
age INT NOT NULL,
can_drive BOOL NOT NULL
)
Now, is it possible to write a single query, which checks to see if an entry ( eg: Fred, 27, true) is in the table, and if it is, returns the id, else inserts the entry and returns the new id?

try:
t=# with i as (
insert into person (name,age,can_drive)
select 'Fred',27,true
where not exists (
select 0 from person where name = 'Fred' and age= 27 and can_drive
)
returning id
)
select * from i
union all
select id from person where name = 'Fred' and age= 27 and can_drive;
id
----
1
(1 row)

Related

Typo in a column name inside a sub-query, but no "Invalid column name" error

I have a table, let's call it A. I want to delete rows with IDs 1 and 2 from that table. For that, I created a table variable #B, containing values 1 and 2 but that column I will name PK.
Now I do this:
DELETE FROM A
WHERE ID IN (
SELECT ID
FROM #B
)
Notice my (deliberate) programming error. In the sub-select, I have used a wrong column name. Accidentally it is the same name used in table A.
This should result in an 'invalid column name' error, right? Except it does not. It executes. Not only that, all data from table A gets deleted. As if there is no more predicate.
I have created a full demo script:
-- What happened to my data???
IF OBJECT_ID('tempdb..#JustATable') IS NOT NULL
DROP TABLE #JustATable
CREATE TABLE #JustATable (
PK INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
ID INT NOT NULL,
NOTE VARCHAR(100) NOT NULL
)
INSERT INTO #JustATable (ID, NOTE)
SELECT database_id, DB_NAME(database_id)
FROM sys.databases;
SELECT NULL [inserted all the rows from sys.databases into the temptable], *
FROM #JustATable;
DECLARE #JustATableVariable TABLE (
PK INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
ID_2 INT NOT NULL,
NOTE VARCHAR(100) NOT NULL
)
INSERT INTO #JustATableVariable (ID_2, NOTE)
SELECT database_id, DB_NAME(database_id)
FROM sys.databases
WHERE database_id = 2;
SELECT NULL [this is my table variable data], *
FROM #JustATableVariable;
DELETE FROM #JustATable
WHERE ID IN (
SELECT ID_2
FROM #JustATableVariable
);
SELECT NULL [I have just removed tempdb from the temptable], *
FROM #JustATable;
DELETE FROM #JustATable
WHERE ID IN (
SELECT ID /* this is the wrong column name but the same name as used in the temptable column */
FROM #JustATableVariable
);
SELECT NULL [wait...where is my data?], *
FROM #JustATable;
Can someone explain to me what is going on here? Has anyone seen this behavior before? Could this be a bug?
In the subquery ... (select id from #b) the column id is not fully qualified. So according to SQL specs, the RDBMS will first see if id column exists in table #b. If it does not, it will search "upwards" until it finds the id column in table a. The query is effectively identical to:
delete from a where id in (select a.id from #b)
Syntactically correct, semantically wrong.

Insert single column return value into multiple columns of another table

I have a db setup like below
create table children_A (
id serial primary key,
value text not null
);
create table children_B (
id serial primary key,
value text not null
);
create table parent_C (
id serial primary key,
child_A_id int not null,
child_B_id int not null
);
and I have an insert query like
with
children_A_insert as ( -- upsert in children_A and return id
insert into children_A(value)
values ('John')
on conflict (value)
do nothing
returning id
),
children_B_insert as ( -- upsert in children_B and return id
insert into children_B(value)
values ('Terry')
on conflict (value)
do nothing
returning id
)
-- insert into parentC(child_A_id, child_B_id) how to write this insert and select query ??
select children.id as id -- how can I trasnlate returning array of intergers into different columns for parent_C table
from (
select id from children_A_insert -- either get newly inserted id
union all
select id from children_A where value = 'John' -- or get the existing id from the children table
union all
select id from children_B_insert
union all
select id from children_B where value = 'Terry'
)
which essentially a query to insert into multiple tables in a single sql command.
result of the query is something like
id
---------
10
12
the problem is I want to take children.id as id and insert the returning ids into the parent table like
id
---------
10
12
should get trasnlated to
child_A_id | child_B_id
10 | 12
in the parent table. Unfortunately, id being a single column can not insert values in parent_C's multiple columns.
Is there a way to use children.id (single column) and insert the values to parent_C's multiple columns.
First of all you must add some constraint in children_A table and children_B table for upsert. Now to achieve the above insert you can try like below:
with
children_A_insert as (
insert into children_A(value)
values ('John')
on conflict (value)
do
update set value=EXCLUDED.value
returning id
),
children_B_insert as (
insert into children_B(value)
values ('Terry')
on conflict (value)
do
update set value=EXCLUDED.value
returning id
)
insert into parent_c (child_A_id,child_B_id)
values((select id from children_A_insert),
(select id from children_B_insert))
DEMO
NOTE: Above will work if you are inserting only one value in each table at a time

How to update a database record and still keep the old values in sql

I have a sql table architecture as
SQL> desc etpro_update;
Name Null? Type
ID NOT NULL NUMBER
NAME VARCHAR2(4000)
IS_ACTIVE NUMBER
CREATED_DATE DATE
where IS_ACTIVE column has been set to default value of 1.So how can we store same data(record) into a table with column IS_ACTIVE having values 0 & 1.
So final output should looks like as below
123 test 1 2017_12_03
123 test 0 2017_12_03
If you want to create a new table with data having IS_ACTIVE as 0 or 1, then try:
create table some_table as
select * from etpro_update
where is_active in (0, 1);
If it's already existing, do INSERT using the SELECT:
insert into some_table (
id,
name,
is_active,
created_date
)
select id,
name,
is_active,
created_date
from etpro_update
where is_active in (0, 1);

Retrieve records through inner join

I have a schema as per the below:
CREATE TABLE rruser (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(30) NOT NULL,
fullname VARCHAR2(100) NOT NULL,
active_flag CHAR(1) DEFAULT 'N' NOT NULL
)
CREATE TABLE rruser_group (
user_id NUMBER(32,0) NOT NULL,
group_id NUMBER(32,0) NOT NULL
)
CREATE TABLE rrgroup (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(100) NOT NULL,
code VARCHAR2(20) NOT NULL
)
CREATE TABLE rrgroup_permission (
group_id NUMBER(32,0) NOT NULL,
permission_id NUMBER(32,0) NOT NULL
)
CREATE TABLE rrpermission (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(100) NOT NULL,
description VARCHAR2(1000) NOT NULL
)
The connectivity is such that RRUSER is linked to RRGROUP via table RRUSER_GROUP
and RRGROUP further linked with RRPERMISSION via table RRGROUP_PERMISSION.
I have to find out the users whose active flag value is equal to 'Y' within RRUSER; I'm using the below query
SELECT * FROM rruser WHERE ACTIVE_FLAG = 'Y'
I then have to find out the users which have write permission; in the last table, RRPERMISSION, there is a column NAME, which has the write permissions where the value of this column is 'write'. What query could I use to get this information? I know it should be achieved using an INNER JOIN.
Right now, I have tried a query for particular user to know whether he has write permission or not and have found out that he has write permission like this...
SELECT count(ID) FROM rruser WHERE ACTIVE_FLAG = 'Y';
SELECT * FROM rruser WHERE ACTIVE_FLAG = 'Y' AND FULLNAME = 'sss'
SELECT * FROM rruser_group WHERE USER_ID = 1100
SELECT * FROM rrgroup WHERE ID = 113;
SELECT * FROM rrgroup_permission WHERE GROUP_ID = 189 ;
SELECT * FROM rrpermission WHERE ID = 990
Try this:
SELECT ru.* FROM rruser ru
inner join rruser_group rg ON ru.id = rg.user_id
inner join rrgroup_permission rgp ON rg.group_id = rgp.group_id
inner join rrpermission rp ON rgp.permission_id = rp.id WHERE ru.ACTIVE_FLAG='Y' AND rp.name='write'

Inserting values into a table based on column values of another table

I would like to insert data into a table based on all the values of a secondary table's column. For example
I have two tables
CREATE TABLE Table1 (
id int identity(1, 1) not null,
FullName varchar(100),
Age int,
CourseID int
)
CREATE TABLE Table2 (
id int identity(1, 1) not null,
Courses int
)
I would like to perform something like this ..
insert into Table1 ('Auser',20,'And the list of Courses that I get from Table2')
Is there a way I can do this in sql server ?
So for one new user you want to insert all available courses?
INSERT INTO Table1
SELECT 'Ausser', 20, t2.Courses
FROM Table2 t2;
Edit: Here's the fiddle: http://sqlfiddle.com/#!3/89470/1/0
Since, you are using SQL Server 2008, you can use the MERGE STATEMENT . Here is a program for your example
CREATE TABLE Table1
(
Id int identity(1, 1) not null,
FullName varchar(100),
Age int,
CourseID int
)
CREATE TABLE Table2
(
ID int identity(1, 1) not null,
Courses int
);
INSERT INTO Table2
SELECT 10 UNION ALL SELECT 20 UNION ALL
SELECT 30 UNION ALL SELECT 40 UNION ALL SELECT 50;
--The Merge Query
MERGE Table1 AS t1
USING (SELECT * FROM Table2) AS t2
ON t1.CourseID= t2.Courses
WHEN NOT MATCHED THEN
INSERT(FullName,Age,CourseID)
VALUES('Ausser',20,t2.Courses);
SELECT *
FROM Table1
DROP TABLE Table1
DROP TABLE Table2
//Result
Id FullName Age CourseID
1 Ausser 20 10
2 Ausser 20 20
3 Ausser 20 30
4 Ausser 20 40
5 Ausser 20 50