Rewrite Oracle SQL Self Join Query - sql

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).

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'.

Join with other table and get aggregated d

I have two table User and Score, each user have multiple score. How can I query average score with user name:
Ex:
Jack 6
Sham 5
User
Name user_id
Jack 123
Tony 234
Sham 456
Score
id score user_id
1 4 123
2 8 123
3 9 234
4 2 456
5 10 456
6 3 456
If I understand, this is a join and group by:
select u.name, avg(s.score)
from users u join
scores s
using (user_id)
group by user_id, u.name;
Note that I've included user_id in the group by, in case two users have the same name.

Aggregate Functions To Pull More Record Field Data

I would like to know what would be the best way to get the data from a specific row when I use a Group By query. The real query is more complex than the example I'm providing here so I'm looking for something other than a sub-select on the Sales table.
I'm using MSSQL 2008 and I would like something that allow me to get the date field from the Sales record that has the max(amount).
Query
select uid, firstName, lastName, AmountFromTagetedRow, DateFromTargetedRow,
from users u inner join
sales s on u.uid = s.custID
group by uid, firstName, lastName
order by uid
USERS
uid firstName lastName
1 Sam Smith
2 Joe Brown
3 Kim Young
SALES
sid Custid date amount ...
1 1 2016-01-02 100
2 3 2016-01-12 485
3 1 2016-01-22 152
4 2 2016-02-01 156
5 1 2016-02-02 12
6 1 2016-03-05 84
7 2 2016-03-10 68
RESULTS
uid firstName LastName amount date
1 Sam Smith 152 2016-01-22
2 Joe Brown 156 2016-02-01
3 Kim Young 485 2016-01-12
Your posted query doesn't match your amount but something like this should get you pointed in the right direction.
with SortedResults as
(
select uid
, firstName
, lastName
, AmountFromTagetedRow
, DateFromTargetedRow
, ROW_NUMBER() over (partition by u.uid order by AmountFromTagetedRow desc) as RowNum
from users u inner join
sales s on u.uid = s.custID
group by uid
, firstName
, lastName
)
select *
from SortedResults
where RowNum = 1
order by uid

SQL Query Joining 2 Tables and Getting Required Data

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;

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