SQL Query Joining 2 Tables and Getting Required Data - sql

I have 2 Tables:
Merchant having 3 columns MerchantID, MemberID, MerchantName
Member having 3 columns MemberID, ReportID, MemberName
The sample values are:
MerchantID MemberID MerchantName
1101 101 ABC
1102 102 DEF
1103 103 XYZ
MemberID ReportID MemberName
101 112 GHI
101 111 JKL
101 115 MNO
102 111 kjh
102 116 hgf
102 117 oiu
103 118 hgh
103 119 jhf
I need to get the MerchantNames which have Member IDs that are not associated with 111 Report ID.
The query o/p should be: XYZ.
Kindly let me know the most optimized SQL query which can achieve this.
Thanks in advance.

This is a classic usecase for the EXISTS operator:
SELECT MerchantName
FROM Merchant
WHERE NOT EXISTS (SELECT 1
FROM Member
WHERE Member.MemberId = Merchant.MemberId AND
ReportId = 111)

with JOIN:
SELECT mer.MerchantName FROM [Merchant] mer
LEFT JOIN [Member] mem ON mer.MemberId = mem.MemberId
AND mem.ReportId != 111;
Or
SELECT mer.MerchantName FROM [Merchant] mer
LEFT JOIN [Member] mem ON mer.MemberId = mem.MemberId
AND mem.ReportId <> 111;

Related

SQL join To Fetch Mutiple Records

I need to find the firstName and Email address from of all teachers and parents in a single query
Here is the structure of the table :
// Patients Table
ID guid parentID PatientName
1 234 1258 John
2 xyz 111 Paul
// Patient_teacher table
ID PatiendGuid teacherid
1 122 132
2 xyz 1424
3 245 1545
4 xyz 1222
// Members table
ID guid email fname
22 123 hello#xyz.com hello
111 xyz parentEmail#xyz.com parentName
1424 343 teacherEmail#xyz.com teacherName
1222 546 teacher2EMail#xyz.com teacher2Name
And Here is the required Result:
//Required Result
fname Email
parentName parentEmail#xyz.com
techerName teacherEmail#xyz.com
teacher2Name teacher2Email#xyz.com
The problem is when I tried to search using join I found a single row that contains parentID and TeacherID
Here is what I tried:
select Members.email,Members.fname
from Members
join Patients on Members.guid = Patients.guid
join Patient_Teacher on Patient_Teacher.patientguid = Patients.guid
where patients.guid = 'xyz'
Here is the Solution :
select Members.id, Members.email, Members.fname
from Patients
join Patient_Teacher on Patient_Teacher.patientguid = Patients.guid
join Members on (Patient_Teacher.teacherid = Members.id
or Patients.parent = Members.id)
where patients.guid = 'xyz'
Have you checked the following reasons?
1- You have a table named 'Patients_teacher' but in your solution, you're referring to it as 'Patient_teacher'.
2- In 'Patients_teacher' table, you have a column named 'patiendguid' but in your solution you're referring to it as 'patientguid'.

Rewrite Oracle SQL Self Join Query

I have the below users and network information in a USER table. I would like to fetch all the Users for a given NetworkID.
ID Name Value Owner
1 UserID 123 111
2 NetworkID 567 111
3 FName ABC 111
4 LName BCD 111
5 UserID 234 222
6 NetworkID 567 222
7 FName DEF 222
8 LName EFG 222
9 UserID 345 333
10 NetworkID 567 333
11 FName GHI 333
12 LName HIJ 333
Below is the Self Join query, I have written to achieve the expected result set
select distinct U1.value NetworkID
, U2.value Users
from User U1
join User U2 on U2.owner = U1.owner and U2.name = 'UserID'
where U1.name = 'NetworkID' and U1.value = '567'
Expected Result
NetworkID Users
567 123
567 234
567 345
The volume of the table is very large and it is taking very long time to fetch the results using this self join. Based on the DB restrictions, I cannot make changes to the existing schema (adding Indexes). I need suggestion on how this query can be rewritten effectively to achieve same result set.
Your query is fine:
select U1.value as NetworkID, U2.value Users
from User U1 join
User U2
on U2.owner = U1.owner and U2.name = 'UserID'
where U1.name = 'NetworkID' and U1.value = '567';
For this query, you want indexes on (owner, name) and (name, value, owner).

How to join three tables in SQL Server 2012 and calculate ranking based on 2 attributes

I have 3 tables:
tblEmployee
E_ID E_Name E_City
--------------------------------
101 sasa Mumbai
102 sdf California
103 trt Illinois
104 dssd Texas
105 trt Pennsylvania
106 wee Arizona
107 rer Texas
108 wqe California
109 sadd Michigan
tblGen
Tgenerate is boolean value
Emp_ID Tgenerate
--------------------
105 1
108 1
102 1
102 1
102 0
104 1
107 0
108 1
109 0
And the tblStat:
Emp_ID Status
------------------
103 Pending
107 Pending
103 Pending
101 Delivered
104 Pending
104 Pending
108 Pending
101 Delivered
105 Delivered
I have to join these 3 tables and want output like this
E_Name EmployeeID City TgenerateCount Delivered_Count Ranking
TgenerateCount is calculated for every employee. It is count of TgenerateCount having value 1, for ex 102 has 2 TgenerateCount and 109 has 0 TgenerateCount.
Delivered_Count is count of Status of those who has 'Delivered' status. For ex. 101 has 2 Delivered. I want to display every user in the output table.
Any help would be greatly appreciated.
As your two fact tables have a many:1 relationship with your dimension table, you should aggregate them before joining them.
SELECT
e.*,
COALESCE(g.rows, 0) AS TgenerateCount,
COALESCE(s.rows, 0) AS DeliveredCount,
RANK() OVER (ORDER BY COALESCE(g.rows, 0) + COALESCE(s.rows,0) DESC) AS ranking
FROM
tblEmployee e
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblGen WHERE Tgenerate = 1 GROUP BY E_ID
)
g
ON g.E_ID = e.E_ID
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblStat WHERE STATUS = 'Delivered' GROUP BY E_ID
)
s
ON s.E_ID = e.E_ID
You've been unclear on how the ranking should be completed, so this simply gives an example ranking.

SQL Server : take 1 to many record set and make 1 record per id

I need some help. I need to take the data from these 3 tables and create an output that looks like below. The plan_name_x and pending_tallyx columns are derived to make one line per claim id. Each claim id can be associated to up to 3 plans and I want to show each plan and tally amounts in one record. What is the best way to do this?
Thanks for any ideas. :)
Output result set needed:
claim_id ac_name plan_name_1 pending_tally1 plan_name_2 Pending_tally2 plan_name_3 pending_tally3
-------- ------- ----------- -------------- ----------- -------------- ----------- --------------
1234 abc cooks delux_prime 22 prime_express 23 standard_prime 2
2341 zzz bakers delpux_prime 22 standard_prime 2 NULL NULL
3412 azb pasta's prime_express 23 NULL NULL NULL NULL
SQL Server 2005 table to use for the above result set:
company_claims
claim_id ac_name
1234 abc cooks
2341 zzz bakers
3412 azb pasta's
claim_plans
claim_id plan_id plan_name
1234 101 delux_prime
1234 102 Prime_express
1234 103 standard_prime
2341 101 delux_prime
2341 103 standard_prime
3412 102 Prime_express
Pending_amounts
claim_id plan_id Pending_tally
1234 101 22
1234 102 23
1234 103 2
2341 101 22
2341 103 2
3412 102 23
If you know that 3 is always the max amount of plans then some left joins will work fine:
select c.claim_id, c.ac_name,
cp1.plan_name as plan_name_1, pa1.pending_tally as pending_tally1,
cp2.plan_name as plan_name_2, pa2.pending_tally as pending_tally2,
cp3.plan_name as plan_name_3, pa3.pending_tally as pending_tally3,
from company_claims c
left join claim_plans cp1 on c.claim_id = cp1.claim_id and cp1.planid = 101
left join claim_plans cp2 on c.claim_id = cp2.claim_id and cp2.planid = 102
left join claim_plans cp3 on c.claim_id = cp3.claim_id and cp3.planid = 103
left join pending_amounts pa1 on cp1.claim_id = pa1.claimid and cp1.planid = pa1.plainid
left join pending_amounts pa2 on cp2.claim_id = pa2.claimid and cp2.planid = pa2.plainid
left join pending_amounts pa3 on cp3.claim_id = pa3.claimid and cp3.planid = pa3.plainid
I would first join all your data so that you get the relevant columns: claim_id, ac_name, plan_name, pending tally.
Then I would add transform this to get plan name and plan tally on different rows, with a label tying them together.
Then it should be easy to pivot.
I would tie these together with common table expressions.
Here's the query:
with X as (
select cc.*, cp.plan_name, pa.pending_tally,
rank() over (partition by cc.claim_id order by plan_name) as r
from company_claims cc
join claim_plans cp on cp.claim_id = cc.claim_id
join pending_amounts pa on pa.claim_id = cp.claim_id
and pa.plan_id = cp.plan_id
), P as (
select
X.claim_id,
x.ac_name,
x.plan_name as value,
'plan_name_' + cast(r as varchar(max)) as label
from x
union all
select
X.claim_id,
x.ac_name,
cast(x.pending_tally as varchar(max)) as value,
'pending_tally' + cast(r as varchar(max)) as label
from x
)
select claim_id, ac_name, [plan_name_1], [pending_tally1],[plan_name_2], [pending_tally2],[plan_name_3], [pending_tally3]
from (select * from P) p
pivot (
max(value)
for label in ([plan_name_1], [pending_tally1],[plan_name_2], [pending_tally2],[plan_name_3], [pending_tally3])
) as pvt
order by pvt.claim_id, ac_name
Here's a fiddle showing it in action: http://sqlfiddle.com/#!3/68f62/10

Google Interview Question: Recursive Query or Common Table Expression for the following scenario

I have two tables TableA and TableB in the following fashion:
Table A(ID, PairId)
--Here the Pair represented by PairId will always have 2 elements in it.
Data:
100,1
101,1
-----
104,2
109,2
TableB(A.ID, GroupId)
--Here the Group represented by GroupId will may have any number of elements.
--Also, A.ID means its a foriegn key from TableA
Data:
100,1000
102,1000
103,1000
--------
101,1001
104,1001
105,1001
-------
105,1002
106,1002
107,1002
Given an id from table A (say X),
Find the ids of its pairmates,
and then the groupmates(of the previous pairmates)
and then the pairmates(of all the ones we found in previous step)
and their groupmates (of all the ones we found in previous step) and so on....
until you dont find any pairmates or groupmates.
For instance, given X as 100
you will accumulate data in this fashion:
Include PairMates
100
101
Include GroupMates(of all the ones in prevstep)
100--groupmates of 100
102
103
101--groupmates of 101
104
105
Include PairMates(of all the ones in the prevstep)
100
102
103
101
104--Pairmate of 104
109
105
Include Groupmates(of all the ones in the prev step)
100
102
103
101
104
109
105--Groupmates of 105
106
107
Include Pairmates( of all the ones in the prevstep)
100
102
103
101
104
109
105
106
107
[None found]
Include Groupmates( of all the ones in the prevstep)
100
102
103
101
104
109
105
106
107
[Nonefound]
---since no pairmates and groupmates were added so the recursion ends
DECLARE #ID INT = <Given ID>
WITH CTE AS
(
SELECT * FROM TABLEB
WHERE ID IN (SELECT ID FROM TABLEA WHERE pairID IN (SELECT pairId FROM TABLEA WHERE ID = #ID))
UNION
SELECT * FROM TABLEB WHERE GroupID IN (SELECT GroupID FROM CTE)
)
SELECT * FROM CTE