I've read that using a where exists clause could usually be more efficient than writing select distinct. How could I rewrite the below 2 queries using the where exists condition? Not sure if query2 is eligible for this clause or this only applies to joins.
Query 1:
SELECT DISTINCT
e.field1,
regexp_substr(substr(TRIM(d.field2), 1, 2), '[A-Za-z]+', 1, 1) postal_group
FROM
table1 e
JOIN table1 f ON f.field0 = e.field0
JOIN table2 g ON g.field3 = f.field3
JOIN table3 g ON g.field4 = f.field4
JOIN table4 a ON a.field5 = g.field5
JOIN table5 b ON ( b.field6 = a.field6
AND b.field7 = a.field7 )
JOIN table6 c ON ( c.field8 = b.field8
AND c.field9 = b.field9 )
JOIN table7 d ON ( d.field10 = c.field10
AND d.field11 = c.field11 )
Query 2:
SELECT DISTINCT
field
FROM
table1
WHERE
condition = 'value'
For your second query you can use group by clause to avoid DISTINCT.
SELECT field
FROM
table1
WHERE
condition = 'value'
Group by field
Please try below query with where exists instead of Distinct:
SELECT
e.field1,
regexp_substr(substr(TRIM(d.field2), 1, 2), '[A-Za-z]+', 1, 1) postal_group
FROM
table1 e
where exists
(
select 1 from table1 f
JOIN table2 g ON g.field3 = f.field3
JOIN table3 g ON g.field4 = f.field4
JOIN table4 a ON a.field5 = g.field5
JOIN table5 b ON ( b.field6 = a.field6
AND b.field7 = a.field7 )
JOIN table6 c ON ( c.field8 = b.field8
AND c.field9 = b.field9 )
JOIN table7 d ON ( d.field10 = c.field10
AND d.field11 = c.field11 )
where f.field0 = e.field0
)
You can't avoid a join with d because you need a column from it. Therefore the best you can do is:
select e.column1
, d.column2 as postal_group
from table1 e
join table7 d
on d.column10 = c.column10
and d.column11 = c.column11
where exists
( select 1 from table1 f
join table2 g on g.column3 = f.column3
join table3 h on h.column4 = f.column4
join table4 a on a.column5 = h.column5
join table5 b on b.column6 = a.column6 and b.column7 = a.column7
join table6 c on c.column8 = b.column8 and c.column9 = b.column9
where f.column0 = e.column0 );
You only need distinct if table7.column2 can have duplicate values for a (column10, column11) combination.
This may or may not be more efficient than the original version - compare timings, execution plans, reads etc.
(I've renamed 'fields' as columns because that's what tables have. Also there are no brackets in a join clause and adding them tends to confuse code formatters.)
Related
with t1 as (
SELECT *
from claim fc
inner join drug_product d
on d.drug_id = d.drug_id
AND d.id = d.id
inner join pharmacy pha
on fc.pharmacy_id = pha.pharmacy_id
and fcnum = pha.num
),
t2 as (
Select d_memberid,
fill_dt,
num,
d_drug_id,
count(distinct device_type) as device_count,
count(device_type),
count(distinct claim_ID)as claim_count
from t1
group by
d_member_id,
fill_dt,
num
)
Select t1.*,
t2.device_count,
d.*
from t1
inner join t2
on t1.num = t2.num
and t1.fill_dt = t2.fill_dt
and t1.d_member_id = t2.d_member_id
inner join drug_product d
on t1.d_drug_id = d.d_drug_id
order by claim_count desc
column ambiguouly defined. Im trying to find if there dup drug fill on the same day. line 54 column 32
column ambigously defined. I wonder if my joins are incorrect. for t1 i join 3 different table for t2 is from the first table. outcome should be a join of the t1 and t2
d_member_hq_id is not prefixed by a table alias, and could be causing the problem if the column name exists in more than 1 table in the from clause. There are other columns which are also not qualified, it is a good practice to qualify all columns to avoid this error.
I have a cursor with a join like so:
CURSOR C1 IS
SELECT *
FROM table_1 a
JOIN table_2 b
ON b.ID_1 = a.ID_1
WHERE TABLE_ID IS NOT NULL
AND TABLE_ID = p_input_id;
I want to modify the cursor and add 3 more joins only if p_input_id IS found in a metadata table. So I want to do something like this:
CURSOR C1 IS
SELECT *
FROM table_1 a
JOIN table_2 b
ON b.ID_1 = a.ID_1
CASE
WHEN EXISTS (SELECT 1
FROM METADATA_TABLE
WHERE INPUT_ID = p_input_id
AND FLAG = 'Y')
THEN
JOIN table_3 c
ON c.ID_2 = b.ID_2
JOIN table_4 d
ON d.ID_3 = c.ID_3
END
WHERE TABLE_ID IS NOT NULL
AND TABLE_ID = p_input_id;
How can I accomplish this? I could consider using LEFT JOIN instead of the case/join. Are there any issues with this?
CURSOR C1 IS
SELECT *
FROM table_1 a
JOIN table_2 b
ON b.ID_1 = a.ID_1
LEFT JOIN table_3 c
ON c.ID_2 = b.ID_2
LEFT JOIN table_4 d
ON d.ID_3 = c.ID_3
WHERE TABLE_ID IS NOT NULL
AND TABLE_ID = p_input_id;
I'm trying to avoid breaking the current cursor for the p_input_id's which are using it. There will be new p_input_id's which need to use the extra table joins.
You can use LEFT JOIN for table_3 and table_4 and count in metadata table as follows:
SELECT * FROM TABLE_1 A
JOIN TABLE_2 B ON B.ID_1 = A.ID_1
JOIN ( SELECT COUNT(1) AS CNT
FROM METADATA_TABLE
WHERE INPUT_ID = P_INPUT_ID
AND FLAG = 'Y') MT
LEFT JOIN TABLE_3 C ON C.ID_2 = B.ID_2
AND MT.CNT > 0
JOIN TABLE_4 D ON D.ID_3 = C.ID_3
AND MT.CNT > 0
WHERE TABLE_ID IS NOT NULL
AND TABLE_ID = P_INPUT_ID;
COUNT is used in the metadata table to ensure that it returns only one record.(replacement of exists)
I have 2 tables - table1 and table2.
In table2, there are multiple records matching criteria for table1 based on:
c_type, h_level, loop, e_id
I want records from RIGHT table ONLY if there is EXACT 1 match. If not, element_nm should be NULL, so I have the exact same records in the output as left table.
SELECT a.*,
b.element_nm
FROM table1 a
LEFT JOIN table2 b ON
a.c_type = b.c_type
AND a.h_level = b.h_level
AND a.loop = b.loop
AND a.e_id = b.e_id
ORDER BY a.file_name,
a.line_num asc;
As this is about one value only, you can use a Sub query in the select clause. Otherwise you'd use a subquery in a LEFT OUTER JOIN or use OUTER APPLY.
SELECT
t1.*,
(
SELECT MIN(t2.element_nm)
FROM table2 t2
WHERE t2.c_type = t1.c_type
AND t2.h_level = t1.h_level
AND t2.loop = t1.loop
AND t2.e_id = t1.e_id
HAVING COUNT(*) = 1
) AS element_nm
FROM table1 t1
ORDER BY t1.file_name, t1.line_num;
Thorsten's answer works when you want only one column from the second table. But if you want multiple columns, it is a bit cumbersome.
Alternatively:
SELECT a.*, b.*
FROM table1 a LEFT JOIN
(SELECT b.*,
COUNT(*) OVER (PARTITION BY b.c_type, b.h_level, b.loop, b.e_id) as cnt
FROM b
) b
ON a.c_type = b.c_type AND
a.h_level = b.h_level AND
a.loop = b.loop AND
a.e_id = b.e_id AND
b.cnt = 1
ORDER BY a.file_name, a.line_num asc;
you should use Row_Number , like this :
WITH cte AS (
SELECT ROW_NUMBER() OVER(PARTITION BY a.c_type ,a.h_level,a.loop ,a.e_id ) rnum
,a.c_type ,a.h_level,a.loop ,a.e_id FROM table1 a
LEFT JOIN table2 b ON a.c_type = b.c_type AND a.h_level = b.h_level AND a.loop = b.loop AND a.e_id = b.e_id
)
,cte2 AS (SELECT * FROM cte WHERE rnum = 2)
SELECT a.*,
CASE WHEN cte2.element_nm IS NULL then b.element_nm ELSE NULL END element_nm
FROM table1 a
LEFT JOIN table2 b ON a.c_type = b.c_type AND a.h_level = b.h_level AND a.loop = b.loop AND a.e_id = b.e_id
LEFT JOIN cte2 ON a.c_type = cte2.c_type AND a.h_level = cte2.h_level AND a.loop = cte2.loop AND a.e_id = cte2.e_id
Is there any alternate way to fetch the following data without using union?
select A.name,A.age,B.Address,C.phoneNo from table1 A,Table2 B,Table3 C where a.pkId = b.FkId and b.pkId = c.FkId
union
select A.name,A.age,B.Address,C.phoneNo from table4 A,Table5 B,Table3 C where a.pkId = b.FkId and b.pkId = c.FkId
I am using this in Hibernate and unfortunately hibernate doesnt support Union. I was just wondering if there is any other way to achieve it else ill have to write it in a procedure and save the data in temp table and fire a sql to read data from that temp table
There is an alternative for union, but it is not pretty:
select distinct coalesce(x1.name, x2.name) as name,
coalesce(x1.age, x2.age) as age,
coalesce(x1.Address, x2.Address) as age,
coalesce(x1.phoneNo, x2.phoneNo) as age,
from (select A.name, A.age, B.Address, C.phoneNo
from table1 A join
Table2 B
on a.pkId = b.FkId join
Table3 C
on b.pkId = c.FkId
) x1 full outer join
(select A.name, A.age, B.Address, C.phoneNo
from table4 A join
Table5 B
on a.pkId = b.FkId join
Table3 C
on b.pkId = c.FkId
) x2
on 1 = 0; -- always false
I can't imagine why you would want to express a union like this. I would highly recommend, though, that you start using proper, explicit join syntax.
is this working ?
SELECT
CASE DISTINCT_FLG WHEN 1 THEN nameA ELSE nameB END name,
CASE DISTINCT_FLG WHEN 1 THEN ageA ELSE ageB END age,
CASE DISTINCT_FLG WHEN 1 THEN AddressA ELSE AddressB END Address,
CASE DISTINCT_FLG WHEN 1 THEN phoneNoA ELSE phoneNoB END phoneNo
FROM (
SELECT
T1.name AS nameA, T1.age AS ageA, T2.Address AS AddressA, T3.phoneNo AS phoneNoA,
T4.name AS nameB, T4.age AS ageB, T5.Address AS AddressB, T3.phoneNo AS phoneNoB,
ROW_NUMBER() OVER(PARTITION BY T1.name, T1.age, T2.Address, T4.name, T4.age, T5.Address, T3.phoneNo ORDER BY NULL) AS DISTINCT_FLG
FROM
table1 T1,
table2 T2,
table4 T4,
table5 T5,
table3 T3
WHERE
T1.pkId = T2.FkId AND
T4.pkId = T5.FkId AND
(
T2.pkId = T3.FkId OR
T5.pkId = T3.FkId
)
) WHERE DISTINCT_FLG IN (1, 2)
Those two UNION parts have Table3 C in common, so we can join the rest to it. To emulate UNION records from the source table can be replicated through unconditional cross join of an auxiliary table with the required number or rows:
Select Distinct
CASE R.r WHEN 1 THEN A1.name ELSE A2.name END As name ,
CASE R.r WHEN 1 THEN A1.age ELSE A2.age END As age ,
CASE R.r WHEN 1 THEN B1.Address ELSE B2.Address END As Address,
C.phoneNo
From Table3 C, --< Start at common Table3
(Select Rownum r From USER_TABLES Where Rownum < 3) R --< Two rows to replicate Table3 C
-- Any table with more than one row will do
-- USER_TABLES should have enough rows in this particular case
Left Join Table2 B1 On R.r = 1 AND B1.pkId = C.FkId --< Left Join branch one
Left Join table1 A1 On R.r = 1 AND A1.pkId = B1.FkId
Left Join Table5 B2 On R.r = 2 AND B2.pkId = C.FkId --< Left Join branch two
Left Join table4 A2 On R.r = 2 AND A2.pkId = B2.FkId
Where (R.r = 1 AND A1.pkId Is NOT NULL) --/ Make sure we have values
OR (R.r = 2 AND A2.pkId Is NOT NULL) --\ for the branch
But really, consider a view.
Please help me through this
sel a.col1,a.co2,a.col3,.........b.col1,b.col2..,c.col1,c.col2
from table1 as a inner join table2 as b on a.col1 =b.col1
inner join table3 as c on a.col1 = b.col1
where col1 = xxxxx;
Now i need join one more table table4. As table4 dont have col1 as primary index in it I need to join this to another table which has Primary key.
The below is the different query which i need inculde this in to the above sel statement.
Sel xx.col1,yy.aaa,yy.bbb,zz.ccc,zz.ddd,zz.eee
from tablea as xx, tableb as yy, table4 as zz
where xx.col1 = yy.bbb and yy.aaa = zz.ccc
Primary indexs :
col1 for table1,table2,table3,tablexx
aaa for tableb
ccc for table4
Thanks in advance
How about:
Select a.leg,c.btn,p.prods,svc.sr,speed.test, a.leg, b.acct_id, e.emp_no, e.emp_name
FROM db1.tb1 as a
inner join db1.tb2 as C ON a.leg = C.leg
inner join db1.tb3 as p ON a.leg = p.leg
inner join db1.tb3 as svc on a.leg = svc.leg
inner join db2.tb4 as speed on a.leg = speed.leg
inner join db4.tb1 as b on a.leg = b.sce_acct_id
inner join db4.tb5 as e on b.acct_id = e.acct_id
where a.leg ='xxxx'