Combining and checking table value on SQL (ORACLE) - sql

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?

Related

How to join the table based on condition in join keys

I have Two table, and I want to join them, but the join key is depend on the condition. For example when table2 column2 value is not represented in table1 start values, I want to join the
on the next value. For example, table2 column2 value 9 is not in start value, and I want to merge on value 10 (next possible value) from start columns.
select * from table1 left join table2 on table2.column2=table1.start or
table2.column2=table1.start+1 or table2.column2=table1.start+2 .. until I find merge value from start columns
You can use the LAG analytic function to find the previous start in table1 and then join between the previous and current values:
SELECT t1.col1,
t1."START",
t2.*
FROM ( SELECT t.*,
LAG("START") OVER (ORDER BY "START") AS prev
FROM table1 t
) t1
LEFT OUTER JOIN table2 t2
ON ((t1.prev IS NULL OR t1.prev < t2.col2) AND t2.col2 <= t1."START")
Which, for the sample data:
CREATE TABLE table1 (col1, "START") AS
SELECT 'a', 10 FROM DUAL UNION ALL
SELECT 'v', 11 FROM DUAL UNION ALL
SELECT 'b', 13 FROM DUAL UNION ALL
SELECT 'r', 14 FROM DUAL;
CREATE TABLE table2 (col1, col2) AS
SELECT 'a', 9 FROM DUAL UNION ALL
SELECT 'q', 10 FROM DUAL UNION ALL
SELECT 's', 11 FROM DUAL UNION ALL
SELECT 'd', 13 FROM DUAL;
Outputs:
COL1
START
COL1
COL2
a
10
a
9
a
10
q
10
v
11
s
11
b
13
d
13
r
14
null
null
fiddle

Dates between date1 and date2 are not working in cross joining

Hi I am trying to filter data with dates between but it insert null 0 rows created its cross joining table I am not aware is there problem due to cross joining or something else. There is no error message
without dates it works fine any solution Please
insert into PAY_IN_OUT2 (EMP_CODE, DATE_IN, DATE_OUT, ATT_DATE, DATE_INA, DATE_OUTA, DATE_INB, DATE_OUTB, DATE_INC, DATE_OUTC, ATT_PRESENT)
select a.EMPLOYEE_ID1, b.DT, b.DT1, B.ATT_DT, B.DT3, B.DT4, B.DT4, B.DT5, B.DT5, B.DT3, 'P'
from CALENDAR_DATES4 b cross join EMPLOYEES a
WHERE A.EMPLOYEE_ID1 BETWEEN 70001 AND 70009
AND B.ATT_DT BETWEEN TO_DATE('10/02/2021', 'DD/MM/YYYY') AND TO_DATE('20/02/2021', 'DD/MM/YYYY') ;
without this its working fine but I have to filter this with dates AND B.ATT_DT BETWEEN TO_DATE('10/02/2021', 'DD/MM/YYYY') AND TO_DATE('20/02/2021', 'DD/MM/YYYY')
If you're cross joining two tables and filtering on each table, and you end up selecting 0 rows, then at least one of your predicates is causing no rows to be returned.
For example, here's a set of queries demonstrating some different results, depending on what the predicates cause to be returned:
WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
SELECT 2 ID, 20 val FROM dual UNION ALL
SELECT 3 ID, 30 val FROM dual UNION ALL
SELECT 4 ID, 40 val FROM dual UNION ALL
SELECT 5 ID, 50 val FROM dual),
t2 AS (SELECT 'A' col1, 'AA' col2 FROM dual UNION ALL
SELECT 'B' col1, 'BA' col2 FROM dual UNION ALL
SELECT 'C' col1, 'AC' col2 FROM dual UNION ALL
SELECT 'D' col1, 'DD' col2 FROM dual)
SELECT 1 case_no, -- case 1: no rows expected to be returned (no t1 rows with an id between 6 and 10)
t1.*,
t2.*
FROM t1
CROSS JOIN t2
WHERE t1.id BETWEEN 6 AND 10
AND t2.col2 LIKE 'A%'
UNION ALL
SELECT 2 case_no, -- case 2: no rows expected to be returned (no t2 rows with a col2 starting with "C")
t1.*,
t2.*
FROM t1
CROSS JOIN t2
WHERE t1.id BETWEEN 2 AND 4
AND t2.col2 LIKE 'C%'
UNION ALL
SELECT 3 case_no, -- case 3: no rows expected to be returned (no t1 rows with an id between 6 and 10, and no t2 rows with a col2 starting with "C")
t1.*,
t2.*
FROM t1
CROSS JOIN t2
WHERE t1.id BETWEEN 6 AND 10
AND t2.col2 LIKE 'C%'
UNION ALL
SELECT 4 case_no, -- case 4: 6 rows expected to be returned (3 t1 rows with an id between 2 and 4, and 2 t2 rows with a col2 starting with "A"; 3 x 2 = 6)
t1.*,
t2.*
FROM t1
CROSS JOIN t2
WHERE t1.id BETWEEN 2 AND 4
AND t2.col2 LIKE 'A%';
CASE_NO ID VAL COL1 COL2
---------- ---------- ---------- ---- ----
4 2 20 A AA
4 3 30 A AA
4 4 40 A AA
4 2 20 C AC
4 3 30 C AC
4 4 40 C AC
You can see that only case 4 (rows in both tables match the predicates) has any rows returned by the cross join.
ETA: if you were wanting to see employee rows regardless of whether there are matching date rows or not, you would need to use an outer join, e.g. using my earlier example, case 2 would become:
WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
SELECT 2 ID, 20 val FROM dual UNION ALL
SELECT 3 ID, 30 val FROM dual UNION ALL
SELECT 4 ID, 40 val FROM dual UNION ALL
SELECT 5 ID, 50 val FROM dual),
t2 AS (SELECT 'A' col1, 'AA' col2 FROM dual UNION ALL
SELECT 'B' col1, 'BA' col2 FROM dual UNION ALL
SELECT 'C' col1, 'AC' col2 FROM dual UNION ALL
SELECT 'D' col1, 'DD' col2 FROM dual)
SELECT t1.*,
t2.*
FROM t1
LEFT OUTER JOIN t2 ON t2.col2 LIKE 'C%'
WHERE t1.id BETWEEN 2 AND 4;
ID VAL COL1 COL2
---------- ---------- ---- ----
2 20
3 30
4 40

Oracle sql - display if record exists else display parent

I want to categorize data into two types based on:
If a value exists in T2, display "A", else display "B" as "Type". Is there a way to implement this in case when or decode?
T1 is the parent of T2.
T1
1
2
3
4
5
T2
1
1
3
3
3
4
Ideally my output would be
Type
A
B
A
A
B
edit: I want to add that A and B are text values I want to display based on my above condition, this is not coming from the db. Also, T2 will not have a corresponding record at all for 2 & 5. so I cannot really check for null.
Try this:
SELECT T1.Col,
CASE WHEN T2.Col IS NOT NULL THEN 'A' ELSE 'B' END AS Type
FROM T1
LEFT JOIN (
SELECT DISTINCT Col FROM T2
) AS T2 ON T1.Col = T2.Col
Oracle Setup:
CREATE TABLE T1 ( column_name ) AS
SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 6;
CREATE TABLE t2 ( column_name ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 1 FROM DUAL UNION ALL
SELECT 3 FROM DUAL UNION ALL
SELECT 3 FROM DUAL UNION ALL
SELECT 4 FROM DUAL;
Query:
SELECT NVL2( T2.column_name, 'A', 'B' ) AS Type
FROM T1
LEFT OUTER JOIN
( SELECT DISTINCT column_name FROM T2 ) T2
ON T1.column_name = T2.column_name
ORDER BY T1.column_name;
Output:
TYPE
----
A
B
A
A
B

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)

How to join oracle tables

I have two tables.
Table 1
ID STRING
1 ABC
2 CDE
3 FGH
Table 2
ID STRING
1 xyz
2 uvw
4 abc
I want the output as
ID STRING STRING2
1 ABC xyz
2 CDE uvw
3 FGH null
4 null abc
which join should I use. Is it possible to do this in simple SQL query?
with
t1 as
(select 1 id, 'ABC' string from dual
union
select 2, 'CDE' from dual
union
select 3, 'FGH' from dual
),
t2 as
(select 1 id, 'xyz' string from dual
union
select 2, 'uvw' from dual
union
select 4, 'abc' from dual)
select COALESCE(t1.id,t2.id) id, t1.string, t2.string string2
from t1 full outer join t2 on (t1.id = t2.id)
order by 1
What you can do is use Union to combine two different result sets. That will give you exactly what you're looking for:
SELECT tab1.ID,
tab1.name,
tab2.name2
FROM tab1 tab1
LEFT JOIN tab2 tab2 ON tab1.ID = tab2.ID
UNION
SELECT tab2.ID,
tab1.name,
tab2.name2
FROM tab1 tab1
RIGHT JOIN tab2 tab2 ON tab1.ID = tab2.ID
You can see that here-> http://sqlfiddle.com/#!4/cf9e2/10
Hope this helps!!!
I guess a full join would be correct
select * from tab1 t1 full join tab2 t2 on t1.id = t2.id