Insert values in two tables using CTE - postgresql

I have two tables (table1 and table2).
The id of table2 is based on the id on table1.
When I insert into table1, I want to get the ids of the newly created rows,
and use it for table2 when I clone the rows but I can't seem to get it right.
Here is a sample that TABLE1 was successfully clone but can't clone TABLE2.
TABLE1:
id | date | status |
----+-------------------------+--------+
1 | 2019-09-05 11:51:53.692 | ACTIVE |
2 | 2019-09-05 11:52:49.32 | ACTIVE |
49 | 2019-09-05 11:51:53.692 | ACTIVE |
50 | 2019-09-05 11:52:49.32 | ACTIVE |
(4 rows)
TABLE2:
id | card_last_digits | card_name |
----+------------+------------------
1 | 4444 | card1 |
2 | 4444 | card2 |
(2 rows)
SQL:
WITH cloneInsert AS (
INSERT INTO table1 (id, date, status)
SELECT nextval('payment_sequence'), date, 'ACTIVE'
FROM table1
RETURNING id)
INSERT INTO table2 (id, card_last_digits, card_name)
SELECT **cloneInsert.id**, card_last_digits, card_name
FROM table2;

You are close - you probably want to select from cloneinsert and insert into table2. Here's sample code that could help
create table test1(
id integer,
msg text
);
create table test2(
id integer,
msg text
);
insert into test1 values (1, 'msg1');
insert into test1 values (2, 'msg2');
with new_rows as (
insert into test1 values (3, 'new message')
returning *)
insert into test2 select id, msg
from new_rows;
> select * from test1;
id | msg
----+-------------
1 | msg1
2 | msg2
3 | new message
(3 rows)
> select * from test2;
id | msg
----+-------------
3 | new message
(1 row)
To make update on test2:
with cte as (
insert into test1 values (3, 'updated message')
returning *)
UPDATE test2
SET id = cte.id, msg = cte.msg
FROM cte WHERE test2.id = cte.id;

Related

Get and combine data from tables postgresql

I'm Nubie.
I want to create a postgresql table by drawing data from several tables
Table1
| partner_id | **project_id** | partner_fund | partner_date |
| 12345 | 099 | 12345.70 | 2003-02-02 |
Table2
| partner_id | partner_name
| 12345 | monster.inc
Table3
| **package_id** | **project_id** |
| 099a | 099 |
Table4
| **package_id** | project_name
| 099a | kill some one
*package_id is corresponding to project_id
I want to make a table like this :
| (if)partner_id | (get)partner_name | (if)project_id (corresponding to package_id)| (get)project_name | partner_fund | partner_date
So, if first row shows partner_id, next column shows partner_name, etc. Please help. Thanks.
You can create a new table from a SELECT query using CREATE TABLE ... AS syntax:
CREATE TABLE new_table AS
SELECT
table1.partner_id,
table2.partner_name,
table3.project_id,
table3.project_name,
table1.partner_fund
FROM table1
INNER JOIN table2 ON (table1.partner_id = table2.partner_id)
INNER JOIN table3 ON (table1.project_id = table3.project_id)
;
...and then you can also add a primary key to the new table, e.g.:
ALTER TABLE new_table ADD PRIMARY KEY (partner_id, project_id);
Query after updated question:
CREATE TABLE new_table AS
SELECT
table1.partner_id,
table2.partner_name,
table1.project_id,
table4.project_name,
table1.partner_fund,
table1.partner_date
FROM table1
INNER JOIN table2 ON (table1.partner_id = table2.partner_id)
INNER JOIN table3 ON (table1.project_id = table3.project_id)
INNER JOIN table4 ON (table3.package_id = table4.package_id)
;

Maintaining order in DB2 "IN" query

This question is based on this one. I'm looking for a solution to that question that works in DB2. Here is the original question:
I have the following table
DROP TABLE IF EXISTS `test`.`foo`;
CREATE TABLE `test`.`foo` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Then I try to get records based on the primary key
SELECT * FROM foo f where f.id IN (2, 3, 1);
I then get the following result
+----+--------+
| id | name |
+----+--------+
| 1 | first |
| 2 | second |
| 3 | third |
+----+--------+
3 rows in set (0.00 sec)
As one can see, the result is ordered by id. What I'm trying to achieve is to get the results ordered in the sequence I'm providing in the query. Given this example it should return
+----+--------+
| id | name |
+----+--------+
| 2 | second |
| 3 | third |
| 1 | first |
+----+--------+
3 rows in set (0.00 sec)
You could use a derived table with the IDs you want, and the order you want, and then join the table in, something like...
SELECT ...
FROM mcscb.mcs_premise prem
JOIN mcscb.mcs_serv_deliv_id serv
ON prem.prem_nb = serv.prem_nb
AND prem.tech_col_user_id = serv.tech_col_user_id
AND prem.tech_col_version = serv.tech_col_version
JOIN (
SELECT 1, '9486154876' FROM SYSIBM.SYSDUMMY1 UNION ALL
SELECT 2, '9403149581' FROM SYSIBM.SYSDUMMY1 UNION ALL
SELECT 3, '9465828230' FROM SYSIBM.SYSDUMMY1
) B (ORD, ID)
ON serv.serv_deliv_id = B.ID
WHERE serv.tech_col_user_id = 'CRSSJEFF'
AND serv.tech_col_version = '00'
ORDER BY B.ORD
You can use derived column to do custom ordering.
select
case
when serv.SERV_DELIV_ID = '9486154876' then 1 ELSE
when serv.SERV_DELIV_ID = '9403149581' then 2 ELSE 3
END END as custom_order,
...
...
ORDER BY custom_order
To make the logic a little bit more evident you might modify the solution provided by bhamby like so:
WITH ordered_in_list (ord, id) as (
VALUES (1, '9486154876'), (2, '9403149581'), (3, '9465828230')
)
SELECT ...
FROM mcscb.mcs_premise prem
JOIN mcscb.mcs_serv_deliv_id serv
ON prem.prem_nb = serv.prem_nb
AND prem.tech_col_user_id = serv.tech_col_user_id
AND prem.tech_col_version = serv.tech_col_version
JOIN ordered_in_list il
ON serv.serv_deliv_id = il.ID
WHERE serv.tech_col_user_id = 'CRSSJEFF'
AND serv.tech_col_version = '00'
ORDER BY il.ORD

Fetch records with distinct value of one column while replacing another col's value when multiple records

I have 2 tables that I need to join based on distinct rid while replacing the column value with having different values in multiple rows. Better explained with an example set below.
CREATE TABLE usr (rid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(12) NOT NULL,
email VARCHAR(20) NOT NULL);
CREATE TABLE usr_loc
(rid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
code CHAR NOT NULL PRIMARY KEY,
loc_id INT NOT NULL PRIMARY KEY);
INSERT INTO usr VALUES
(1,'John','john#product'),
(2,'Linda','linda#product'),
(3,'Greg','greg#product'),
(4,'Kate','kate#product'),
(5,'Johny','johny#product'),
(6,'Mary','mary#test');
INSERT INTO usr_loc VALUES
(1,'A',4532),
(1,'I',4538),
(1,'I',4545),
(2,'I',3123),
(3,'A',4512),
(3,'A',4527),
(4,'I',4567),
(4,'A',4565),
(5,'I',4512),
(6,'I',4567);
(6,'I',4569);
Required Result Set
+-----+-------+------+-----------------+
| rid | name | Code | email |
+-----+-------+------+-----------------+
| 1 | John | B | 'john#product' |
| 2 | Linda | I | 'linda#product' |
| 3 | Greg | A | 'greg#product' |
| 4 | Kate | B | 'kate#product' |
| 5 | Johny | I | 'johny#product' |
| 6 | Mary | I | 'mary#test' |
+-----+-------+------+-----------------+
I have tried some queries to join and some to count but lost with the one which exactly satisfies the whole scenario.
The query I came up with is
SELECT distinct(a.rid)as rid, a.name, a.email, 'B' as code
FROM usr
JOIN usr_loc b ON a.rid=b.rid
WHERE a.rid IN (SELECT rid FROM usr_loc GROUP BY rid HAVING COUNT(*) > 1);`
You need to group by the users and count how many occurrences you have in usr_loc. If more than a single one, then replace the code by B. See below:
select
rid,
name,
case when cnt > 1 then 'B' else min_code end as code,
email
from (
select u.rid, u.name, u.email, min(l.code) as min_code, count(*) as cnt
from usr u
join usr_loc l on l.rid = u.rid
group by u.rid, u.name, u.email
) x;
Seems to me that you are using MySQL, rather than IBM DB2. Is that so?

Complex TSQL MultiRow Insert with OutPut

I have a temp table as follows
DECLARE #InsertedRows TABLE (RevId INT, FooId INT)
I also have two other tables
Foo(FooId INT, MyData NVarchar(20))
Revisions(RevId INT, CreatedTimeStamp DATETIME)
For each row in Foo, I need to a) insert a row into Revisions and b) insert a row into #InsertedRows with the corresponding Id values from Foo and Revisions.
I've tried writing something using the Insert Output Select as follows:
INSERT INTO Revisions (CURRENT_TIMESTAMP)
OUTPUT Inserted.RevId, Foo.FooId INTO #InsertedRows
SELECT FooId From Foo
However, Foo.Id is not allowed in the Output column list. Also, the Id returned in the SELECT isn't inserted into the table, so that's another issue.
How can I resolve this?
You cannot reference the FROM table in an OUTPUT clause with an INSERT statement. You can only do this with a DELETE, UPDATE, or MERGE statement.
From the MSDN page on the OUTPUT clause (https://msdn.microsoft.com/en-us/library/ms177564.aspx)
from_table_name Is a column prefix that specifies a table included in
the FROM clause of a DELETE, UPDATE, or MERGE statement that is used
to specify the rows to update or delete.
You can use a MERGE statement to accomplish what you are asking.
In the below example, I changed the tables to be all variable tables so that this could be run as an independent query and I changed the ID columns to IDENTITY columns which increment differently to illustrate the relationship.
The ON clause (1=0) will always evaluate to NOT MATCHED. This means that all records in the USING statement will be used to insert into the target table. Additionally the FROM table in the USING statement will be available to use in the OUTPUT statement.
DECLARE #Foo TABLE (FooId INT IDENTITY(1,1), MyData NVarchar(20))
DECLARE #Revisions TABLE (RevId INT IDENTITY(100,10), CreatedTimeStamp DATETIME)
DECLARE #InsertedRows TABLE (RevId INT, FooId INT)
INSERT INTO #Foo VALUES ('FooData1'), ('FooData2'), ('FooData3')
MERGE #Revisions AS [Revisions]
USING (SELECT FooId FROM #Foo) AS [Foo]
ON (1=0)
WHEN NOT MATCHED THEN
INSERT (CreatedTimeStamp) VALUES (CURRENT_TIMESTAMP)
OUTPUT INSERTED.RevId, Foo.FooId INTO #InsertedRows;
SELECT * FROM #Foo
SELECT * FROM #Revisions
SELECT * FROM #InsertedRows
Table results from above query
#Foo table
+-------+----------+
| FooId | MyData |
+-------+----------+
| 1 | FooData1 |
| 2 | FooData2 |
| 3 | FooData3 |
+-------+----------+
#Revisions table
+-------+-------------------------+
| RevId | CreatedTimeStamp |
+-------+-------------------------+
| 100 | 2016-03-31 14:48:39.733 |
| 110 | 2016-03-31 14:48:39.733 |
| 120 | 2016-03-31 14:48:39.733 |
+-------+-------------------------+
#InsertedRows table
+-------+-------+
| RevId | FooId |
+-------+-------+
| 100 | 1 |
| 110 | 2 |
| 120 | 3 |
+-------+-------+

SQL query for insert into with a set of constants

It seems like there should be a query for this, but I can't think of how to do it.
I've got a table with a composite primary key consisting of two fields I'd like to populate with data,
I can do an insert into from one table to fill up half the keys, but I want to fill up the other half with a set of constants (0, 3, 5, 6, 9) etc...
so the end result would look like this
+--------------+
|AwesomeTable |
+--------------+
| Id1 | Id2 |
| 1 | 0 |
| 1 | 3 |
| 1 | 5 |
| 1 | 6 |
| 1 | 9 |
| 2 | 0 |
| 2 | 3 |
| ... | ... |
+--------------+
I've got as far as insert into awesometable (id1, id2) select id1, [need something here] from table1 [need something else here]
I've got a table with 2 primary keys
No, you don't. A table can only have one primary key. You probably mean a composite primary key.
I believe you want this:
INSERT
INTO awesometable (id1, id2)
SELECT t1.id1, q.id2
FROM table1 t1
CROSS JOIN
(
SELECT 0 AS id2
UNION ALL
SELECT 3
UNION ALL
SELECT 5
UNION ALL
SELECT 6
UNION ALL
SELECT 9
) q
, or in Oracle:
INSERT
INTO awesometable (id1, id2)
SELECT t1.id1, q.id2
FROM table1 t1
CROSS JOIN
(
SELECT 0 AS id2
FROM dual
UNION ALL
SELECT 3
FROM dual
UNION ALL
SELECT 5
FROM dual
UNION ALL
SELECT 6
FROM dual
UNION ALL
SELECT 9
FROM dual
) q
If I understand correctly, maybe you can use something like this:
insert into awesometable (id1, id2)
select id1, (select top 1 id2 from table2 where /*a condition here to retreive only one result*/)
from table1