Postgresql SELECT LEFT JOIN with columns on case - sql

SELECT a1,a2,a3,a4,count(a5),b1,b2,b3
FROM table1
LEFT JOIN table2 ON a1=b1 AND a2=b2 (*here i need to join
next columns a3=b3 only if from table2 will be returned more than 1 records
other wise first 2 columns will be enough*)
group by a1,a2,a3,a4,a5,b1,b2,b3
Anybody knows how to perform this trick ?

Well, if I understand correctly:
FROM table1 t1 LEFT JOIN
(SELECT t2.*, COUNT(*) OVER (PARTITION BY b1, b2) as cnt
FROM table2 t2
)
ON t1.a1 = t2.b1 AND t1.a2 = t2.b2 AND
(cnt = 1 OR t1.a3 = t2.a3)

Related

Multiple search between two tables

I have two tables - the first (this is just an example but the original query is a pretty big)
item_id_t1
serial_num_t1
country_t1
customer
snapshot_date_t1
serial_num_trunc_t1
156648107
222-99950578
AAA
BBSS
12/1/2022
99950578
156648107
222-99950578
AAA
BBSS
11/1/2022
99950578
156648107
222-99950578
AAA
BBSS
1/1/2023
99950578
108279887
888-515179765
AAA
BBSS
12/1/2022
515179765
108279887
888-515179765
AAA
BBSS
11/1/2022
515179765
108279887
888-515179765
AAA
BBSS
11/1/2023
515179765
and the second one
serial_num_trunc_t2
serial_num_t2
up_ind_t2
99950578
333-99950578
1
515179765
888-515179765
1
Now, my first step would be to find a match based on serial_num_t1 = serial_num_t2 and the second part of the code should be to find all unmatched records but this time based on serial_num_trunc_t1 = serial_num_trunc_t2.
I started with CTE tables first
WITH t1 AS (SELECT * FROM t1),
t2 AS (SELECT * FROM t2)
SELECT a.*
(SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON serial_num_t1 = serial_num_t2) a
INNER JOIN
(SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t1
WHERE q.up_ind_t2 <> 1) b
ON a.serial_num_trunc_t1 = b.serial_num_trunc_t2
and here I am stuck. How to compare unmatched values from table "a" again with table "b" based ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t2 WHERE t2.ip_ind_t2 <> 1
My final table should have six records (like t1) and "up_ind_t2" should be filled with 1 for all six records in the final table.
I would appreciate your help.
I am guessing, you want
WITH t1 AS (SELECT * FROM t1),
t2 AS (SELECT * FROM t2)
SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON serial_num_t1 = serial_num_t2
UNION ALL
SELECT t1.*, t2.*
FROM t1
INNER JOIN t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t1
WHERE q.up_ind_t2 <> 1
as Query,the LEft JOIN doesn't make that much sense in the firstplace, so i removed ot from the second.
the second query implies that you have only 1 record for every serial_num_trunc_t2 and that is not equal to 1, if not you need to add limit
#nbk
It doesn't look like my solution. I added match_level in order to see from where a match comes: from LEFT JOIN or from INNER JOIN (UNION part of the code).
So, when I run your code I get the same results as before UNION ALL part
WITH t1 AS (SELECT * FROM ib),
t2 AS (SELECT * FROM qu)
SELECT t1.*, t2.*, 1 as match_level
FROM ib t1
LEFT JOIN qu t2
ON serial_num_t1 = serial_num_t2
UNION ALL
SELECT t1.*, t2.*, 2 as match_level
FROM ib t1
INNER JOIN qu t2
ON t1.serial_num_trunc_t1 = t2.serial_num_trunc_t2
WHERE t2.up_ind_t2 <> 1
Finally, this is what I needed.
with
ib as (
select *
from [dbo].[ib] i
left join [dbo].[qu] q
on i.serial_num_t1=q.serial_num_t2),
qu as (
select *
from [dbo].[ib] i
right join [dbo].[qu] q
on i.serial_num_trunc_t1=q.serial_num_trunc_t2)
select ff.*
from
(select *
from
(select ROW_NUMBER() OVER(PARTITION BY q.item_id_t1,
q.serial_num_t1,q.country_t1, q.customer, q.snapshot_date_t1,
q.up_ind_t2 ORDER BY q.snapshot_date_t1, q.up_ind_t2 DESC) AS it_row, q.*
from qu q
left join ib b
on q.serial_num_trunc_t2 = b.serial_num_trunc_t1) a
union
select 99 as it_row, zz.*
from qu as zz ) ff
where it_row = 1

column ambigously defined

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.

Select Multiple value from a table but group by one value

I am trying to select multiple values from two tables but i want to group by single value. I have tried using max(value) in select but max is returning the greatest one and not the exact one.
Here are my tables
The result i need is something like this
Result : HeadQuarterId - A, PropertyName - Name1, Amount - 102
HeadQuarterId - B, PropertyName - Name5, Amount - 30
Here is my query
SELECT Headquarterid,Max(PropertyName),sum(Amount)
FROM Table1 A LEFT OUTER JOIN Table2 B
ON A.Propetyid = B.PropertyId
GROUP BY Headquarterid
Here i have used Left Outer Join so that i will get all the data from left table even it is not available in right table.
Also i cannot use A.HeadquarterID = A.PropertyId in where condition since i have other dependency in that table. Please suggest someother way to achieve this result.
I think I understand. You want the headquarters with the maximum value, which happens to be A. If so:
select t1.*, sum(t2.amount) over () as total
from t1 left join
t2
on t2.PropertyId = t1.PropertyId
order by t2.amount desc
fetch first 1 row only;
Note: Not all databases support fetch first. It might be spelled limit or use select top (1) for instance.
I would recommend to get the headquartename per ID in a cte / subquery, then join it again to T1 and left join T1 to T2 in a second cte / subquery. This way you can calculate your sums basing on a single group:
WITH cte AS(
SELECT ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY CASE WHEN t1.ID = t1.PROPERTYID THEN 0 ELSE 1 END) rn, t1.ID, t1.Name
FROM t1
),
cte2 AS(
SELECT c.name cName, t1.*, t2.Value
FROM t1
INNER JOIN cte c ON c.ID = t1.ID AND c.rn = 1
LEFT JOIN t2 ON t1.Propertyid = t2.propertyid
)
SELECT c2.id, c2.cname, sum(c2.value) value
FROM cte2 c2
GROUP BY c2.id, c2.cname
See SQLFiddle for details: http://sqlfiddle.com/#!18/8bf66/13/2
Of course you can build the first cte without the row_number only by using the WHERE ID = PROPERTYID - matter of taste I'd say...
As per your sample data you want window function :
select distinct t1.HeadQuarterId,
max(t1.PropertyName) over (partition by t1.HeadQuarterId) as PropertyName,
sum(t2.amount) over (partition by t1.HeadQuarterId) as amount
from t1 left join
t2
on t2.PropertyId = t1.PropertyId;
This provided the result i expected.
SELECT HQTRS1 AS headId,Max(LLORD1) AS headName, sum(Amount) AS amount
FROM
(SELECT DISTINCT HeadQuarterId AS HQTRS1, PropertyName AS LLORD1 FROM Table_1 WHERE HeadQuarterId = PropertyId) AS temp
INNER JOIN Table_1 AS A ON A.HeadQuarterId = temp.HQTRS1
LEFT OUTER JOIN Table_2 B
ON B.PropertyId = A.PropertyId
GROUP BY HQTRS1

JOIN TWO TABLES WITH KEY VALUES IN TABLE 1 WITH ALL KEY VALUES IN TABLE 2

I have two tables
Table 1: With Column Name Key
Values:
C1
C2
C3
C4
Table 2: with three columns Product, Category, count
P1-C1-2
P1-C3-4
P2-C1-3
P2-C2-4,
P2-C3-8,
P3-C3-10,
P3-C4-2,
Output required:
P1-C1-2
P1-C2-0
P1-C3-0
P1-C4-0
P2-C1-3
P2-C2-4,
P2-C3-8,
P2-C4-0,
P3-C1-0,
P3-C2-0,
P3-C3-10,
P3-C4-2
Is there any way to do it?
Thanks in Advance
You are looking for cross join
select distinct t2.Product, t1.Key, coalesce(t3.count, 0) as count
from table2 t2 cross join (select [Key] from table1) t1
left join table2 t3
on t3.Product = t2.Product and t1.[key] = t3.Category
Looks like you want to use the cross-join:
SELECT [* | column_list]
FROM table1
CROSS JOIN table2;
More on the subject
SELECT t2.Product,t2.Category, case when t2.Category=t1.Category then t2.count ELSE 0 END AS count
FROM table1 t1,table2 t2;

Alternative for union in Oracle

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.