SQL - Selecting a value from conditional joins without UNION - sql

Setup
create table things ( `t1_id` int, `t2_id` int);
insert into things (`t1_id`, `t2_id`)
values ( NULL, 1), (NULL, 2), (1, NULL),(2,NULL);
create table type_1 (`id` int, `name` TEXT);
insert into type_1 (`id`, `name`)
values (1, 'name 1'), (2, 'name2');
create table type_2 (`id` int, `name` TEXT);
insert into type_2 (`id`, `name`)
values (1, 'name 3'), (2, 'name4');
Query
select coalesce (t1.name, t2.name) as name
from things
join type_1 as t1 on things.t1_id IS NOT NULL AND things.t1_id = t1.id
join type_2 as t2 on things.t2_id IS NOT NULL AND things.t2_id = t2.id
group by name
Fiddle: http://sqlfiddle.com/#!9/cfce11/7
I have what I've set out in the fiddle working with UNION, but in reality the rest of the query is expensive and the union doubled this - I'll probably need to do this for a second column too (name2 from type_3 and type_4 could be in this example, things would always have either t1_id or t2_id and either t3_id or t4_id - I'm assuming the same solution would work).
I'm looking for name to be selected from one table or another depending on whether the relevant column in 'things' is null.. I could use a 'type' column in things to differentiate if it would be better.
The fiddle should return all 4 names.

You are inner joining t1 and t2, but a thing cannot match t1 and t2 at the same time, so you get no results.
Join query
select distinct coalesce (t1.name, t2.name) as name
from things
left join type_1 as t1 on things.t1_id = t1.id
left join type_2 as t2 on things.t2_id = t2.id;
Union query
select name from type_1 where id in (select t1_id from things)
union
select name from type_2 where id in (select t2_id from things);
Both queries do the same thing. They give you all distinct names that are referenced in the things table.

Related

move all values from column in one table to new table and update third table with relation between those tables, PostgreSQL

I am using SQL after a long time and I have following:
I have existing table1 with columns id, name and a lot of other columns, it already contains rows.
I created empty table2 which only has columns id and name.
I created empty table3 which only has reference columns table1_id and table2_id.
Now I want to:
take all the values from column name in table1 (can be NULL, discard them in that case),
insert them as new rows into table2,
insert ids of the corresponding table1 and table2 rows into table3,
remove the column name from table1.
=> probably ALTER TABLE table1 DROP COLUMN name;, but I guess there may be a neater way to cut the result from step 1, transform it and paste as rows in step 2.
EDIT: I came up with something like (not tested yet):
SELECT table1.id, table1.name INTO results FROM table1;
FOR result1 IN
results
LOOP
WITH result2 AS (
INSERT INTO table2 (name) VALUES (result1.name) RETURNING id
)
INSERT INTO table3 (table2_id, table1_id) VALUES (result2.id, result1.id);
END LOOP;
ALTER TABLE table1 DROP COLUMN name;
EDIT:
I forgot to tell that if the name already existed in table2, I don't want to add it again (should be unique in table2), but I add the relation between the id from table1 and from the inserted/existing id from table2 into the table3.
EDIT:
I found we have source scripts for creating the database and I changed it there. Now I don't know how to get rid of this open question :(
For steps 1) & 2):
--Since you already have a table2
DROP TABLE table2;
--Create new table2 with data. Unless you are going to replace NULL with something
--discarding them would just end up with NULL again.
CREATE table2 AS SELECT id, name from table1;
Step 3). Not sure of the purpose of table3 as you would have matching id values between table1 and table2. In fact you could use that to set up a FOREIGN KEY relationship between them.
Step 4) Your solution: ALTER TABLE table1 DROP COLUMN name;
Not sure how you want to use it. If you want to run it as one-time transformation in one bulk, this could help (you can try the code on sqlfiddle):
CREATE TABLE table1 (
id int,
name varchar(9)
);
INSERT INTO table1 (
id,
name
)
VALUES
(1, 'A'),
(2, null),
(3, 'C'),
(4, null),
(5, 'E'),
(6, 'C')
;
CREATE TABLE table2 (
id SERIAL,
name varchar(9) UNIQUE
);
INSERT INTO table2 (name)
SELECT DISTINCT name
FROM table1
WHERE name IS NOT NULL
;
/*
-- This would be better option, but I was not able to test the merge/upsert function of PostgreSQL
INSERT INTO table2 (name)
SELECT name
FROM table1
WHERE name IS NOT NULL
ON CONFLICT table2_name_key DO NOTHING --merge/upsert, supports PostgreSQL 9.5 and newer
;
*/
CREATE TABLE table3 (
id_table1 int,
id_table2 int
) AS
SELECT
t1.id id_table1,
t2.id id_table2
FROM table1 t1
INNER JOIN table2 t2
ON t1.name = t2.name
;
--ALTER TABLE table1 DROP COLUMN name;
This could also be useful:
stackoverflow_1
postgresqltutorial
stackoverflow_2
postgresql documentation with PL/pgSQL code - suggestion you wrote in question is going much more this way

Receiving duplicated results from UNION in SQL

I use SQL Server I use the following code:
CREATE TABLE table1
(
ID VARCHAR(10) NOT NULL PRIMARY KEY,
Name VARCHAR(3) NOT NULL,
Price INTEGER NOT NULL,
Date DATE
);
INSERT INTO table1 (ID, Name, Price, Date)
VALUES ('000212', 'Rod', 200, NULL);
CREATE TABLE table2
(
Descr VARCHAR(10) NOT NULL PRIMARY KEY,
Identity VARCHAR(10) NOT NULL,
amount INTEGER NOT NULL
);
INSERT INTO table2 (Descr, Identity, amount)
VALUES ('Silver rod', '000212', 3);
CREATE TABLE table3
(
Type VARCHAR(5) NOT NULL PRIMARY KEY,
Price INTEGER,
Condition INTEGER NOT NULL,
CatalogNum VARCHAR(10) NOT NULL
);
INSERT INTO table3 (Type, Price, Condition, CatalogNum)
VALUES ('Metal', NULL, 8, '000212');
INSERT INTO table3 (Type, Price, Condition, CatalogNum)
VALUES ('Wood', 300, 1, '000313');
WITH IdList AS
(
SELECT ID AS MasterId
FROM table1
UNION
SELECT Identity
FROM table2
UNION
SELECT CatalogNum
FROM table3
)
SELECT
i.MasterID,
t1.*,
t2.*,
t3.*
FROM
IdList as i
LEFT JOIN
table1 as t1 ON t1.ID = i.MasterID
LEFT JOIN
table2 as t2 ON t2.Identity = i.MasterID
LEFT JOIN
table3 as t3 ON t3.CatalogNum = i.MasterID;
SQL Fiddle demo
In order to combine several tables with the same product ID.
However for some reason I get multiple duplicated results. I.E. instead of getting one row with unique ID, I get 7 (I currently have 7 tables unlike the code above, but not necessarily - I also get 2, and 3 duplicated rows) with the same result.
Just to mention, this is a code which I found here and just edited and added 7 tables instead of only three that in the example above.

SQL - Multiple Inner Join, most recent

I am wondering why the below SQL query does not work properly. I am attempting to return the fields from table 1 and table 2 based on the most recent date AND only those elements in those tables that have the name Steve from a third table.
This query, meanwhile, does not actually limit the results to those with the name of Steve. If I remove the second Inner Join and focus on fields only in Table 1 to limit the universe, it works fine.
Appreciate your help on this. I am using Microsft SQL Server Management Studio.
Select *
From [db].table1
INNER JOIN [db].table2 ON table1.id=table2.id
INNER JOIN [db].table3 ON table1.id=table3.id
WHERE (table1.AsOfDate=(SELECT MAX(AsOfDate) from [db].table1))
and table3.Name = 'Steve'
The ID's may not be referring to the same ID across all three tables. Your joins assumes that is the case though. I mirrored your query with sample temp tables and your query works.
--SAMPLE TABLES
IF object_id('tempdb..#table1') is not null drop table #table1
if object_id('tempdb..#table2') is not null drop table #table2
if object_id('tempdb..#table3') is not null drop table #table3
CREATE TABLE #table1 (id INT, my_date date)
INSERT INTO #table1 (id, my_date) VALUES
(1, '1/1/2018'),
(2, '1/2/2018'),
(3, '1/1/2018')
CREATE TABLE #table2 (id INT, some_field VARCHAR(10))
INSERT INTO #table2 (id, some_field) VALUES
(1, 'abc'),
(2, 'xyz'),
(3, 'foo')
CREATE TABLE #table3 (id INT, name VARCHAR(10))
INSERT INTO #table3 (id, name) VALUES
(1, 'jon'),
(2, 'steve'),
(3, 'jane')
--QUERY
SELECT *
FROM #table1 AS x
INNER JOIN
#table2 AS y ON x.id=y.id
INNER JOIN
#table3 AS z ON z.id=x.id
WHERE x.my_date=(SELECT MAX(my_date) from #table1)
and z.name = 'Steve'
output
id my_date id some_field id name
2 2018-01-02 2 xyz 2 steve
I think the simplest way is a window function in the order by:
Select top (1) with ties . . . -- list the columns explicitly
from [db].table1 t1 join
[db].table2 t2
on t1.id = t2.id join
[db].table3 t3
on t1.id = t3.id
where t3.Name = 'Steve'
order by rank() over (order by t1.AsOfDate);

select mutiple columns from 1 table insert into multiple rows of another table

how do I select multiple columns from table1 and insert into multiple rows of table2 if the values is not null
create table table2
(
label_id NUMBER(4),
level_name VARCHAR2(20)
);
create table table1
(
level_name VARCHAR2(20),
class_name1 VARCHAR2(20),
class_name2 VARCHAR2(20),
class_name3 VARCHARS2(20)
)
create table table2
(
level_id NUMBER(4),
class_name VARCHAR2(20)
)
data in table0
1, k1
2, k2
data in table1
k1, roomA5, roomA6, roomA7
k2, roomB1, roomB2
the result table2
1, roomA5
1, roomA6
1, roomA7
2, roomB1
2, roomB2
I probably need to add another column in table2 to make it right. perhaps table2 should be(level_id, room_id, class_name)
thank you so much for the any help
Try with:
insert into Table2 t2
(
Level_Id,
Class_Name
)select
t0.Level_Id,
t1.Class_Name1
from Table0 t0
inner join Table1 t1 on t1.level_name = t0.level_name
Do it with each class, just must replace Class_Name1 with Class_Name2.
Here is how to do it, easy if you union all 3 select statements for each classname column.
insert into table2
select a.level_id, b.classname1
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname1 is not null
union all
select a.level_id, b.classname2
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname2 is not null
union all
select a.level_id, b.classname3
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname3 is not null
Have you looked at the unpivot command?
http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
Of course, this assumes you are using oracle 11g, which is an assumption at this point.
insert into table2
select *
from table1
unpivot
(
level_name
for class_name in ("class_name1","class_name2","class_name3")
)
order by "Puchase Frequency", state_code
I don't have a DB to test with, but this might help. It seems like a clean way to do it.

JOIN - Get one full table and the rest of another

Hi guys here is my Schema: http://sqlfiddle.com/#!4/82771
CREATE TABLE t1
(
Age INT,
Name VARCHAR(20)
);
CREATE TABLE t2
(
Age INT,
Name VARCHAR(20)
);
INSERT INTO t1(Age, Name) VALUES(31, NULL);
INSERT INTO t1(Age, Name) VALUES(32, NULL);
INSERT INTO t1(Age, Name) VALUES(33, NULL);
INSERT INTO t1(Age, Name) VALUES(34, NULL);
INSERT INTO t2(Age, Name) VALUES(31, 'Panos');
I need a Join query that will give me this Result:
Age Name
31 'Panos'
32 Null
33 Null
34 Null
I've tried LEFT JOIN and RIGHT JOIN on Age but I can't get what I need. It should be pretty simple but its just not coming to me...
maybe you have missed something when you are doing LEFT JOIN. Use also coalesce to return the first non-null value.
SELECT t1.Age, COALESCE(t2.name, t1.Name) Name
FROM t1
LEFT JOIN t2
ON t1.Age = t2.Age
SQLFiddle Demo
One way is to use union all and then check for non-existence in the second table:
select *
from t1
union all
select *
from t2
where Not exists (select 1 from t1 where t1.age = t2.age)