JOIN - Get one full table and the rest of another - sql

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)

Related

SQL - Selecting a value from conditional joins without UNION

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.

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);

How to make sql (postgresql) query?

/* Create a table called tbl1 */
CREATE TABLE tbl1(id integer PRIMARY KEY, name text, lang text);
/* Create few records in this table */
INSERT INTO tbl1 VALUES(1,'John', 'Perl');
INSERT INTO tbl1 VALUES(2,'Pete', 'Perl');
INSERT INTO tbl1 VALUES(3,'Sam', 'Java');
INSERT INTO tbl1 VALUES(4,'John', 'Php');
INSERT INTO tbl1 VALUES(5,'Sam', 'Perl');
INSERT INTO tbl1 VALUES(6,'Sam', 'Php');
INSERT INTO tbl1 VALUES(7,'Pete', 'C');
INSERT INTO tbl1 VALUES(8,'Bob', 'Java');
Derive the names of those who know Perl and Php.
The OP contained very Little information. Is this what you need?
SELECT Name
FROM tbl1
WHERE lang = 'Perl' AND lang = 'Php'
For future reference; you really should provide a minimal working example, as you have done here, but also what you have actually tried, which you lacked.
If this query is what you need, then it is very straight-forward and your problem should have been managable with just googling some minutes.
SELECT distinct(name)
FROM tbl1
WHERE name IN (SELECT name FROM tbl1 WHERE lang = 'Perl')
AND name IN (SELECT name FROM tbl1 WHERE lang = 'Php');
Is it good answer? I don't think so.
I want to find better way.
2 additional answers
SELECT n FROM (
SELECT tbl1.name, string_agg(tbl1.lang, '-')
FROM tbl1
GROUP BY name) AS t (n, l)
WHERE
position('Perl' in l) <> 0
AND
position('Php' in l) <> 0;
===================================
SELECT t1.name FROM (
SELECT name FROM tbl1 WHERE lang = 'Perl'
) AS t1, (
SELECT name FROM tbl1 WHERE lang = 'Php'
) AS t2
WHERE t1.name = t2.name;

SQL Join on partial column data (SQL Server)

Both columns are tinyint if it matters.
Table1
Version
--------
111115
222226
333337
Table2
ID Year
--------
5 2015
6 2016
7 2017
I need to join on the ID from table 2 if it equals the last value in the version field from table 1.
Version 111115 would join to ID 5. I know how to select on things like this but is joining feasible? The result being:
111115 5 2015
TIA!
You can use the RIGHT() function to do this:
SELECT *
FROM Table1 A
INNER JOIN Table2 B on RIGHT(A.Version,1) = B.ID
I would probably avoid having to do this very much though. It is a faulty database design. Perhaps add a column ID to table 1, and use:
UPDATE Table1
SET ID = RIGHT(Version,1)
Since they are both integer, you can try the modulus operator. It takes the remainder after division. So 111115 % 10 is 5.
SELECT *
FROM Table1 t1
INNER JOIN Table2 t2 on t1.Version % 10 = t2.ID
Declare #tblTest as table
(
id INT,
yearName INT
)
Declare #tblVersion as table
(
VersionNo INT
)
INSERT INTO #tblTest values(5,2015)
INSERT INTO #tblTest values(6,2016)
INSERT INTO #tblTest values(7,2017)
INSERT INTO #tblVersion values(111115)
INSERT INTO #tblVersion values(111116)
INSERT INTO #tblVersion values(111117)
select
*,RIGHT(VersionNo,1)
from #tblVersion
SELECT
*
FROM #tblTest T1
LEFT JOIN (SELECT RIGHT(VersionNo,1) AS VersionId,VersionNo FROM #tblVersion) T2 ON T2.VersionId=T1.id

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.