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
Related
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
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?
I have 2 tables :
tab_1 :
ID VAL
1 Y
2 N
3 Y
tab_2 :
ID VAL
2 N
3 X
4 Y
I want to get the final output like
ID Operation
1 INSERT
2 EQUAL
3 DIFF
4 DEL
I am in very basic level in joins so need some help in explanation/understanding this type of functionalities.Thanks in advance.
It appears that you want a full outer join between the two tables; and then a case expression to compare the val columns (both their existence and values) in both tables. Maybe something like:
-- CTEs for sample data
with tab_1 (ID, VAL) as (
select 1, 'Y' from dual
union all select 2, 'N' from dual
union all select 3, 'Y' from dual
),
tab_2 (ID, VAL) as (
select 2, 'N' from dual
union all select 3, 'X' from dual
union all select 4, 'Y' from dual
)
-- actual query
select coalesce(t1.id, t2.id) as id,
case
when t1.id is null then 'DEL'
when t2.id is null then 'INSERT'
when t2.val = t1.val then 'EQUAL'
else 'DIFF'
end as operation
from tab_1 t1
full outer join tab_2 t2 on t2.id = t1.id
order by id;
ID OPERATION
---------- ---------
1 INSERT
2 EQUAL
3 DIFF
4 DEL
I have to join 2 tables with SQL in a special way:
TABLE1 has the fields GROUP and MEMBER, TABLE2 has the fields GROUP and MASTER.
I have to build a new TABLE3 with the fields GROUP and ID by copying TABLE1 to TABLE3 and search TABLE2 if there is a GROUP from TABLE1 and if, copy GROUP and MASTER to TABLE3.
Example:
table1:
group member
1 a
1 b
1 c
2 x
3 y
table2:
group master
3 n
3 z
1 k
9 v
2 m
7 o
8 p
Expected result, table3:
group id
1 a from table1
1 b from table1
1 c from table1
1 k from table2
2 x from table1
2 m from table2
3 y from table1
3 z from table2
3 n from table2
I hope everything's clear.
So what is the SQL query?
Thanks, Hein
The first part (copy members) should be easy:
INSERT INTO table3 (group, id) SELECT group, member FROM table1;
Then You just copy the masters, that are in groups, that are already present in table1:
INSERT INTO table3 (group, id) SELECT group, master FROM table2 WHERE group IN (SELECT DISTINCT group FROM table1);
Try this out. Of course you need to INSERT the whole selection to your new table named Table3.
WITH TABLE1(GRP,MMBR) AS
(SELECT 1, 'a' FROM DUAL UNION ALL
SELECT 1, 'b' FROM DUAL UNION ALL
SELECT 1, 'c' FROM DUAL UNION ALL
SELECT 2, 'x' FROM DUAL UNION ALL
SELECT 3, 'y' FROM DUAL),
TABLE2(GRP,MSTR) AS
(SELECT 3, 'n' FROM DUAL UNION ALL
SELECT 3, 'z' FROM DUAL UNION ALL
SELECT 1, 'k' FROM DUAL UNION ALL
SELECT 9, 'v' FROM DUAL UNION ALL
SELECT 2, 'm' FROM DUAL UNION ALL
SELECT 7, 'o' FROM DUAL UNION ALL
SELECT 8, 'p' FROM DUAL)
SELECT * FROM (
SELECT GRP, MMBR ID FROM TABLE1
UNION --UNION ALL if you need duplicates
SELECT GRP, MSTR ID FROM TABLE2
WHERE TABLE2.GRP IN (SELECT GRP FROM TABLE1)
)
ORDER BY GRP, ID
You can do it using UNION ALL and 2 simple SELECT in an INSERT as follows:
INSERT INTO table3(group,id)
SELECT group,id FROM table1
UNION ALL
SELECT group,id FROM table2
SELECT * FROM table3;
And if you don't want duplicate values,try this using UNION instead of UNION ALL:
INSERT INTO table3(group,id)
SELECT group,id FROM table1
UNION
SELECT group,id FROM table2
SELECT * FROM table3;
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