Select data from two tables with no join condition, t-sql - sql

I'd appreciate if someone could help.
I have two tables that have no relationship:
Table_1
ID NAME VALUE
1 abc 10
2 def 20
3 def 20
Table_2
ID2 NAME2 VALUE2
5 ghi 30
6 gkl 40
I want to have a select statement that would show the data from both tables like this:
ID NAME VALUE ID2 NAME2 VALUE2
1 abc 10 5 ghi 30
2 def 20 6 gkl 40
3 def 20
The point is to show data of each record in one row, the table can look like:
ID NAME VALUE ID2 NAME2 VALUE2
5 ghi 30
6 gkl 40
If Table_1 has no records. Same is true for Table_2.
I tried to use cross join, but then the data will repeat.
Thanks a lot

You need to add a join condition. In this case, by using row_number() to add a sequential number on each side. Then full outer join to get all the records:
select t1.id, t1.name, t1.value, t2.id as id2, t2.name as name2, t2.value as value2
from (select t1.*, row_number() over (order by id) as seqnum
from table_1 t1
) t1 full outer join
(select t2.*, row_number() over (order by id) as seqnum
from table_2 t2
) t2
on t1.seqnum = t2.seqnum;

Try this:
with Table_1(ID, NAME, VALUE) as (
select 1, 'abc', 10 union all
select 2, 'def', 20 union all
select 3, 'def', 20
), Table_2(ID2, NAME2, VALUE2) as (
select 5, 'ghi', 30 union all
select 6, 'gkl', 40
), prep_table_1 (ID, NAME, VALUE, rn) as (
select id, name, value, row_number() over(order by id)
from table_1
), prep_table_2 (ID2, NAME2, VALUE2, rn) as (
select id2, name2, value2, row_number() over(order by id2)
from table_2
)
select t1.ID, t1.NAME, t1.VALUE, t2.ID2, t2.NAME2, t2.VALUE2
from prep_table_1 t1
full outer join prep_table_2 t2 on t1.rn = t2.rn
SQLFiddle

This also works
select * from Table_1,Table_2

Related

Combining and checking table value on SQL (ORACLE)

Table 1
no name col1
1 a a_1
2 b b_1
Table 2
id name parent
a_1 zz c_1
b_1 yy d_1
c_1 aa null
d_1 bb e_1
e_1 dd1 null
what i want to show is showing the all list name. for example table 1 name a has col1 name a_1 it will show the name on table 2, and then check the parent in the table 2 and show it and keep checking until it found null. the example is like below.. im sorry for my bad explanation
t1_name t2_name t2_name t2_name
a zz aa
b yy bb dd1
or shows like below
t1_name t2_name
a aa/zz
b dd1/bb/yy
what I've done is this query
select t1.name,t2.name as folder from table1 as t1 inner join table2 as t2 on t1.col1=t2.id
and I don't know how to check again in query... I am using oracle version 12.2.0.1.0 in SQL developer any help?
You want to get the rows from the first table and then recursively fetch all the rows from the second table until you reach a null parent, so you do:
with cte(NAME,
PARENT,
CURRENTPATH) as
(select t1.NAME,
t2.PARENT,
t2.NAME as CURRENTPATH
from TABLE1 t1
join TABLE2 t2 on t1.COL1 = t2.ID
union all
select t1.NAME,
t2.PARENT,
t1.CURRENTPATH || '/' || t2.NAME as CURRENTPATH
from cte t1
join TABLE2 t2 on t2.ID = t1.PARENT)
select NAME,
CURRENTPATH
from cte
where PARENT is null;
You can use the hierarchical query as following:
SQL> -- Your data
SQL> with table1(no,name,col1) as
2 (SELECT 1, 'a','a_1' FROM DUAL UNION ALL
3 SELECT 2, 'b','b_1' FROM DUAL
4 ),
5 table2 (id, name, parent) as
6 (select 'a_1', 'zz', 'c_1' from dual union all
7 select 'b_1', 'yy', 'd_1' from dual union all
8 select 'c_1', 'aa', null from dual union all
9 select 'd_1', 'bb', 'e_1' from dual union all
10 select 'e_1', 'dd1', null from dual)
11 -- Your query starts from here
12 SELECT
13 T1.NAME AS T1_NAME,
14 T2.NAMES AS T2_NAMES
15 FROM TABLE1 T1
16 JOIN (
17 SELECT
18 T2.ID,
19 SYS_CONNECT_BY_PATH(T2.NAME, '/') AS NAMES,
20 ROW_NUMBER() OVER(PARTITION BY ID ORDER BY LEVEL DESC) AS L
21 FROM TABLE2 T2
22 CONNECT BY T2.PARENT = PRIOR T2.ID
23 ) T2 ON T1.COL1 = T2.ID
24 WHERE L = 1;
T1_NAME T2_NAMES
------- ---------------
a /aa/zz
b /dd1/bb/yy
SQL>
Cheers!!
Which Oracle version are you using?

UNION ALL Trick ORACLE

This may be so easy, but I can not figure out how I can do.
so my code is like this
FOR example
SELECT id,total,total2
FROM (select id, 0 AS total ,t1.total AS total2
FROM table1 t1
union ALL
select id, t2.total AS total, 0 AS total2
FRoM table2 t2)
it shows
id------total------totals
001 0 20
001 15 0
I would like to show like this
id------total------totals
001 15 20
How can I do that?
Thank you so much
Do an aggregation afterwards:
SELECT id, sum(total) as total, sum(total2) as total2
FROM (select id, 0 AS total ,t1.total AS total2
FROM table1 t1
union ALL
select id, t2.total AS total, 0 AS total2
FRoM table2 t2
) i
GROUP BY id;
Instead of dumping 0's into some columns as filler, you can use a WITH and subquery's to retrieve a sum on all records in the matching Id's from a distinct list of Id's.
;WITH GetIds AS (
SELECT DISTINCT id
FROM table1
UNION
SELECT DISTINCT id
FROM table2
)
SELECT id,
(SELECT SUM(total) FROM table1 t1 WHERE t1.id = ids.id) AS total1,
(SELECT SUM(total) FROM table2 t2 WHERE t2.id = ids.id) AS total2
FROM GetIds ids

SQL Complex join not giving distinct result

I have two tables :-
Table1:-
ID1
1
1
1
1
4
5
Table2:-
Id2
2
2
1
1
1
8
I want to show all the ID2 from table2 which are present in ID1 of table1 by using joins
I used :-
select ID2 from Table2 t2 left join Table1 t1
on t2.Id2=t1.Id1
But this was giving repeated result as :-
Id2
1
1
1
1
1
1
1
It should show me 1 as 3 times only as it is present in Table2 3 times.
Please help.
You're matching the value 1 with 4 rows on Table1 and 3 rows on Table2 that's why you're seeing 12 rows. You need an additional JOIN condition. You can add a ROW_NUMBER and do an INNER JOIN to achieve your desired result.
WITH Cte1 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id1 ORDER BY (SELECT NULL))
FROM Table1
),
Cte2 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id2 ORDER BY (SELECT NULL))
FROM Table2
)
SELECT c2.Id2
FROM Cte2 c2
INNER JOIN Cte1 c1
ON c1.Id1 = c2.Id2
AND c1.rn = c2.rn
However, you can achieve the desired result without using a JOIN.
SELECT *
FROM Table2 t2
WHERE EXISTS(
SELECT 1 FROM Table1 t1 WHERE t1.Id1 = t2.Id2
)
It's the expected behavior of Join Operation. It will match every row from the two tables, so you will get 12 rows containing value 1 in result of join query.
You can use below query to get desired result.
select ID2 from Table2 t2 WHERE ID2 IN (SELECT ID1 FROM Table1 t1)
select id2 from table2 t2 where exists ( select 1 from table1 t1 where t1.id1 = t2.id2)
Your join logic works fine, the problem is each of your ID2 is matching against all ID1s. A simple solution would be to join with a table of distinct ID1s to avoid this duplication.
select
t2.ID2
from Table2 t2
left join (select distinct * from Table1) t1
on t1.Id1=t2.Id2
where t1.ID1 is not null
;
Here is a functional example
This will select your entire ID2 list with ID1 populated in a column. ID1 is null where there was no match. Select your ID2 column from this table but just don't pull null values (with where clause):

require to form a sql query

I was working on preparing a query where I was stuck.
Consider tables below:
table1
id key col1
-- --- -----
1 1 abc
2 2 d
3 3 s
4 4 xyz
table2
id col1 foreignkey
-- ---- ----------
1 12 1
2 13 1
3 14 1
4 12 2
5 13 2
Now what I need is to select only those records from table1 for which the corresponding entries in table2 does not have say col1 value as 12.
So the challenge is after applying join even though it will skip for value 1 corresponding to col1 equal to 12 it still has another multiple rows whose values are say 13, 14 for which also they have same foreignkey. Now what I want is if there is a single row having value 12 then it should not pick that id at all from table1.
How can I form a query with this?
The output which i need is say from above table structure i want to get those records from table1 for which col1 value from table2 does not have value as 14.
so my query should return me only row 2 from table1 and not row 1.
Another way of doing that. The first two queries are just for making the sample data.
;WITH t1(id ,[key] ,col1) AS
(
SELECT 1 , 1 , 'abc' UNION ALL
SELECT 2 , 2 , 'd' UNION ALL
SELECT 3 , 3 , 's' UNION ALL
SELECT 4 , 4 , 'xyz'
)
,t2(id ,col1, foreignkey) AS
(
SELECT 1 , 12 , 1 UNION ALL
SELECT 2 , 13 , 1 UNION ALL
SELECT 3 , 14 , 1 UNION ALL
SELECT 4 ,12 , 2 UNION ALL
SELECT 5 ,13 , 2
)
SELECT id, [key], col1
FROM t1
WHERE id NOT IN (SELECT t2.Id
FROM t2
INNER JOIN t1 ON t1.Id = t2.foreignkey
WHERE t2.col1 = 14)
This is a typical case for NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE NOT EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id AND t2.col1 = 14)
The above query will not select a row from table1 if there is a single correlated row in table2 having col1 = 14.
Output:
id key col1
-------------
2 2 d
3 3 s
4 4 xyz
If you want to return records that, in addition to the criterion set above, also have correlated records in table2, then you can use the following query:
SELECT t1.id, MAX(t1.[key]) AS [key], MAX(t1.col1) AS col1
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.foreignkey
GROUP BY t1.id
HAVING COUNT(CASE WHEN t2.col1 = 14 THEN 1 END) = 0
Output:
id key col1
-------------
2 2 d
You can also achieve the same result with the second query using a combination of EXISTS and NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id)
AND
NOT EXISTS (SELECT 1
FROM table2 t3
WHERE t3.foreignkey = t1.id AND t3.col1 = 14)
select t1.id,t1.key,
(select ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1 DESC) AS Row,* into
#Temp from table1)
from table1 t1
inner join table2 t2 on t1.id=t2.foreignkey
where t2.col1=(select col1 from #temp where row>1)

Max rows by group

Current SQL:
select t1.*
from table t1
where t1.id in ('2', '3', '4')
Current results:
id | seq
---+----
3 | 5
2 | 7
2 | 5
3 | 7
4 | 3
Attempt to select maxes:
select t1.*
from table t1
where t1.id in ('2', '3', '4')
and t1.seq = (select max(t2.seq)
from table2 t2
where t2.id = t1.id)
This obviously does not work since I'm using an in list. How can I adjust my SQL to get these expected results:
id | seq
---+----
2 | 7
3 | 7
4 | 3
Group By is your friend:
SELECT
id,
MAX(seq) seq
FROM TABLE
GROUP BY id
EDIT: Response to comment. To get the rest of the data from the table matching the max seq and id just join back to the table:
SELECT t1.*
FROM TABLE t1
INNER JOIN (
SELECT
id
MAX(seq) as seq
FROM TABLE
GROUP BY id
) as t2
on t1.id = t2.id
and t1.seq = t2.seq
EDIT: Gordon and Jean-Francois are correct you can also use the ROW_NUMBER() analytic function to get the same result. You need to check the performance difference for your application (I did not check). Here is an example of that:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER (
PARTITION BY id
ORDER BY seq DESC) as row_num
,*
FROM TABLE
) as TMP
WHERE row_num = 1
This SQL Query will give you max seq from individaul ID.
SELECT t1.*
FROM t1
WHERE t1.id in ('2', '3', '4')
AND NOT EXISTS (
SELECT *
FROM t1 t2
WHERE t2.id = t1.id
AND t2.seq > t1.seq
select *
from table
where (id,seq) in
(
select id,max(seq)
from table
group by id
having id in ('2','3','4')
);
That is if id and/or seq are completely part of the PK of that table.
Here's another example, using the first/last method I mentioned earlier in the comments:
with sd as (select 3 id, 5 seq, 1 dummy from dual union all
select 2 id, 7 seq, 2 dummy from dual union all
select 2 id, 5 seq, 3 dummy from dual union all
select 3 id, 7 seq, 4 dummy from dual union all
select 3 id, 7 seq, 5 dummy from dual union all
select 4 id, 3 seq, 6 dummy from dual)
select id,
max(seq) max_seq,
max(dummy) keep (dense_rank first order by seq desc) max_rows_dummy
from sd
group by id;
ID MAX_SEQ MAX_ROWS_DUMMY
---------- ---------- --------------
2 7 2
3 7 5
4 3 6
The keep (dense_rank first order by ...) bit is requesting to keep the values associated with the rank of 1 in the order list of rows. The max(...) bit is there in case more then one row has a rank of 1; it's just a way of breaking ties.