Postgres - insert and composite foreign keys - sql

Say I have a table with the following columns:
a: integer
b: integer
c: integer
d: integer
code: text
(a, b) is a foreign key to another table 1
(c, d) is a foreign key to another table 2
Inserting is easy:
INSERT INTO table(a, b, c, d, code) VALUES(x1, y1, x2, y2, 'my code')
Now, I would like to insert while fetching the values of my composite foreign keys a,b and c,d in a subquery. Something like this:
INSERT INTO table(a, b, c, d, code) VALUES
((SELECT a, b FROM other-table-1 WHERE ...),
(SELECT c, d FROM other-table-2 WHERE ...), 'my code')
The query above doesn't work ofcourse, but it illustrates what I am trying to achieve.
Another try, but also not working (the sub-query has to return one column):
INSERT INTO table(a, b, code)
SELECT (SELECT a, b FROM other-table-1 WHERE ...),
(SELECT c, d FROM other-table-2 WHERE ...), 'my code')
Is this somehow possible?

You have to use the below syntax to insert records, if 'my code' is always is the static
INSERT INTO table(a, b, code)
SELECT a, b, 'my code' FROM other-table WHERE ...
If you have multiple table, then you can use syntax like this using CTE
INSERT INTO table(a, b, c, d, code)
WITH t1 AS (
SELECT a, b FROM other-table-1 WHERE ...
), t2 AS (
SELECT c, d FROM other-table-2 WHERE ...
)
select t1.a, t1.b, t2.c, t2.d, 'my code' from t1,t2

Your query should be structuerd something like this:
INSERT INTO table(a, b, c, d, code)
SELECT x.a, x.b, y.c, y.d, 'my code' FROM other-table-1 AS x
CROSS JOIN other-table-2 AS y
WHERE ...

Related

Using multiple CTE with multiple temp tables

In Windows Server, I am trying to gather data using multiple CTEs insert them into a few temp tables to later on perform a join. Below is what I got. :
------TEMP TABLE SET UP------
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#LEFT')
)
BEGIN
DROP TABLE #LEFT
END
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#RIGHT')
)
BEGIN
DROP TABLE #RIGHT
END
------TEMP TABLE SET UP END------
------CTE SET UP------
; with
CTEfirst (1a, b, c, d) as
(select 1a, b, c, d from tableA)
, CTEone (a, b, c) as
(select a, b, c from table1)
),
CTEtwo (a, b, c) as (
(select a, b, c from table2)
),
CTEthree (a, b, c) as (
(select a, b, c from table3)
------CTE SET UP END------
select * into #LEFT from CTEone
union
select * from CTEtwo
union
select * from CTEthree
-----------------------------
/*At this point I am getting the issue to recognize CTEfirst when attempting to insert data into #RIGHT temp table unless I move the below portion below the previous section (prior to the unions) but then would encounter the issue of the overall query not recognizing the next CTE, CTEone.*/
select * into #RIGHT from CTEfirst
Thank you
you have declared cte but it is empty
; with
CTEfirst (a, b, c, d)
as ( select ...) --<-- missing cte definiation here
, CTEone (a, b, c) as
(select a, b, c from table1)
),
You cannot refer to the same CTE for more than one unattached select statement.
Your first query ends when you insert into #left.
After that you cannot run a new select statement referring to the same (unattached) CTEs.
Think of CTEs as reformatted sub-queries. If you want data loaded into multiple temp tables, I wouldn't use CTEs in the first place. Just insert into the temp tables directly.

UNION without comparing one of the columns

I have two queries
select A, B, C, D from T1, T2
select A, B, C, D from T2, T3
I want to do a UNION of the two queries (no duplicates) but not comparing column D, that is if columns A B and C are the same then they are considered duplicates regardless of D. I do not want to select from joined tables T1, T2, and T3. Is this possible on a single statement?
(this is Oracle)
Use UNION and GROUP BY to do this, like following;)
select A, B, C
from(
select A, B, C, D from T1, T2
union
select A, B, C, D from T2, T3
)t
group by A, B, C
And you have to specify which D value do you want to get when A, B, C are the same, here I assume you get max(D), like this;
select A, B, C, max(D) as D
from(
select A, B, C, D from T1, T2
union
select A, B, C, D from T2, T3
)t
group by A, B, C
No matter which value you want to reserve, when you use group by in oracle, you only can select columns which appear in group by or some other columns with aggregation functions.

Select distinct on multiple columns simultaneously, and keep one column in PostgreSQL

For a table such as this:
tblA
A,B,C
1,2,t3a
1,3,d4g
1,2,b5e
1,3,s6u
I want to produce a table that selects distinct on both A and B simultaneously, and still keep one value of C, like so:
tblB
A,B,C
1,2,t3a
1,3,d4g
Seems like this would be simple, but not finding it for the life of me.
DROP TABLE IF EXISTS tblA CASCADE;
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA;
When you use DISTINCT ON you should have ORDER BY:
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA
ORDER BY A, B;
This should do the trick
CREATE TABLE tblB AS (
SELECT A, B, max(C) AS max_of_C FROM tblA GROUP BY A, B
)
Use a view to do the distinct and then join it to the original table to pick one row of column C. Inserting into the target is left for you to figure out. Oh, and you could pick up multiple columns from t, not just c - the only thing is that your subquery needs to find a way to limit it to only one row.
create table t (a int, b int, c int);
create view tv as select distinct a, b from t;
insert into t (a, b, c) values(1, 2, 10);
insert into t (a, b, c) values(1, 2, 20);
insert into t (a, b, c) values(1, 3, 30);
insert into t (a, b, c) values(1, 3, 40);
CREATE TABLE tblB AS (
select tv.a, tv.b, t.c from tv, t
where tv.a = t.a and tv.b = t.b
/* pick smallest ctid which is a unique row id built into postgres */
and t.ctid = (select min(ctid) from t s where s.a = t.a and s.b = t.b);
)

Dynamic conditional insert in postgresql

I am attempting to define a conditional insert in postgresql, on an index over 3 columns (which gives uniqueness). I'm trying to follow the following example from the postgresql documentation:
INSERT INTO example_table
(id, name)
SELECT 1, 'John'
WHERE
NOT EXISTS (
SELECT id FROM example_table WHERE id = 1
);
For the basic SELECT WHERE NOT EXISTS structure. But if the index varies, i.e. you want to prevent insert if there exists a selection in the table with id=index value of current pre-insert row, how do you implement this? Here is my current (wrong) code:
insert = (
"INSERT INTO table (index,a,b,c,d,e)"
"SELECT * FROM table WHERE NOT EXISTS (SELECT * FROM table WHERE index=index)");
cur.execute(insert,data)
For clarity, the index is defined on data columns (a,b,c), data is a row of (index,a,b,c,d,e), and I'm wrapping this in psycopg2. I have searched for an answer for a while, but haven't been able to successfully adapt anything to this problem yet.
insert into t1 (a, b, c, d, e)
select a, b, c, d, e
from t2
where not exists (
select 1
from t1
where a = t2.a and b = t2.b and c = t2.c
);
In Python it is easier and cleaner to use the triple quote raw string
insert = """
insert into t1 (a, b, c, d, e)
select a, b, c, d, e
from t2
where not exists (
select 1
from t1
where a = t2.a and b = t2.b and c = t2.c
);
"""

SQL Server 2005: Using select in case statement

I have a temporary table whose data is populated from another table using select.
For eg.,
Table1's fields:
A, B, C
Table2's fields
A, D, E --A is foreign key from TableA
#sometemp's fields
X, Y, Z
insert into #sometemp (X, Y, Z)
select D, E, case
when (Table1's C is 0) then 0
when (Table1's C is 1) then somefunction(#arg1, #arg2)
end
from Table2
I cant figure it out how Table1's C value can be checked in the when clauses. Any ideas?