MSSQL join query with Group by - sql

my table structure like this:
ID SID Type Description SN
82 372 PC XX 1234ZZ
83 372 Monitor YYY 2234ZZ
587 444 PC BBB 2255XX
588 444 Monitor CCC 4512XC
i would like to create a VIEW to show all record in same row group by SID (Staff ID)
my sql as follows:
SELECT DISTINCT a.SID,
CAST(b.Description AS NVARCHAR(100)) AS Name_PC,
CAST(b.SN AS NVARCHAR(100)) AS SN_PC,
CAST(c.Description AS NVARCHAR(100)) AS Name_Monitor,
CAST(c.SN AS NVARCHAR(100)) AS SN_Monitor,
dbo.StaffDB.DisplayName
FROM dbo.IT_Equ AS a INNER JOIN
dbo.StaffDB ON a.SID = dbo.StaffDB.SID LEFT OUTER JOIN
dbo.IT_Equ AS b ON a.SID = b.SID AND b.Type = 'PC' LEFT OUTER JOIN
dbo.IT_Equ AS c ON a.SID = c.SID AND c.Type = 'Monitor'
WHERE (b.Description IS NOT NULL) AND (b.SN IS NOT NULL)
AND (c.Description IS NOT NULL) AND (c.SN IS NOT NULL)
GROUP BY a.SID, CAST(b.Description AS NVARCHAR(100)),
CAST(b.SN AS NVARCHAR(100)),
CAST(c.Description AS NVARCHAR(100)),
CAST(c.SN AS NVARCHAR(100)),
StaffDB.DisplayName
the code works fine if staf only had one record for PC and monitor, it will show the following results:
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
372 XX 1234ZZ YYY 2234ZZ Peter
444 BBB 2255XX CCC 4512XC John
but if the staff had more than one PC record or monitor record, it will create duplicate records such as
original record in db:
ID SID Type Description SN
106 476 PC PC018 84TK5
107 476 Monitor LCD018 60P5D
421 476 PC PC220 85HYC
422 476 Monitor LCD220 51RMR
the result like this:
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
476 PC018 84TK5 LCD018 60P5D Mary
476 PC018 84TK5 LCD220 51RMR Mary
476 PC220 85HYC LCD018 60P5D Mary
476 PC220 85HYC LCD220 51RMR Mary
is it possible to enhance the query to become this ?
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
476 PC018 84TK5 LCD018 60P5D Mary
476 PC220 85HYC LCD220 51RMR Mary
thanks

Problem is in the data - you have to fix duplicates. Obviously 1 monitor belongs to 2 PCs -
PC018 - 60P5D and PC220 - 60P5D.
Alternatively you can try to arrange them and somehow to take 1st SN for the 1st PC and so on, but I don't think this is the right way.

how to you want to determine which sn_pc you want to use?
A distinct will not solve your problem, a distinct only eliminate identical lines.
You have to aggregate if it's possible : min(sn_pc)
You can use view function : row_number over (partition by sid, name_pc order by sn_pc) in a subquery then where rownum = 1
But when reading again the results, it seems you are missing a join criteria when joining your tables
dbo.IT_Equ AS c ON a.SID = c.SID AND c.Type = 'Monitor'
Here is the problem, use a subquery to only select the last line if possible.

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

Joining table twice with output based n new table

I am having trouble joining a table twice on the same column.
Table People
name
phone_number
Pamela
113 555 7544
Jordan
328 555 9658
Haley
502 555 6712
Table Phone_calls
caller
receiver
duration
113 555 7544
328 555 9658
234
328 555 9658
502 555 6712
500
502 555 6712
113 555 7544
468
Desired output
duration
caller_name
receiver_name
234
Pamela
Jordan
SELECT name as caller_name, name as receiver_name, duration
FROM people
JOIN phone_calls ON people.phone_number=phone_calls.caller
JOIN phone_calls ON people.phone_number=phone_calls.receiver
ORDER BY duration;
How should differentiate the two name links I want to output?
This is where aliases make for an easier query:
select pc.duration, c.Name as Caller_name, r.Name as Receiver_name
from Phone_calls pc
join People c on c.phone_number = pc.caller
join People r on r.phone_number = pc.receiver
order by pc.duration;
I'm not sure if I understood your question correctly but, assuming the desired output you've mentioned is indeed the output you desire, this query correctly returns your output:
create table people (
nome varchar(50) primary key,
phone_number varchar(50)
);
insert into people values ('Pamela', '113 555 7544');
insert into people values ('Jordan', '328 555 9658');
insert into people values ('Haley', '502 555 6712');
select * from people;
create table phone_calls (
caller varchar(50),
receiver varchar(50),
durations int
);
insert into phone_calls values ('113 555 7544', '328 555 9658', 234);
insert into phone_calls values ('328 555 9658', '502 555 6712', 500);
insert into phone_calls values ('502 555 6712', '113 555 7544', 468);
select
tt.durations,
tt.caller_name,
p.nome as "receiver_name"
from
(
select
pc.durations,
p.nome as caller_name,
pc.receiver as telefone
from people p
left join phone_calls pc
on p.phone_number = pc.caller
) tt
left join people p
on tt.telefone = p.phone_number
where tt.caller_name = 'Pamela';

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

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;

Access Query; Creating Master/Slave from list

Asked a question a few days ago, but have decided to go down a differnt route so am re-doing the question as the edit's were getting a bit messy.
I have a list of data containing two columns:
pID sKey
100 8611
100 2318
101 3516
101 5413
102 6546
102 5646
102 8411
103 8795
103 5845
The first sKey to appear would become the Master sKey for that pID and each sKey after would be a slave. The data would look like this.
pID sKey sKey_1
100 8611 2318
101 3516 5413
102 6546 5646
102 6546 8411
103 8795 5845
This query gets me close
SELECT MyTable.pID, MyTable.sKey, MyTable_1.sKey
FROM MyTable
INNER JOIN MyTable AS MyTable_1
ON MyTable.pID = MyTable_1.pID
WHERE (((IIf([MyTable.sKey]=[MyTable_1.sKey],"Y","N"))="N"))
pID sKey sKey
100 2318 8611
100 8611 2318
101 3516 5413
101 5413 3516
102 5646 6546
102 5646 8411
102 6546 5646
102 6546 8411
102 8411 5646
102 8411 6546
103 5845 8795
103 8795 5845
But as you can see it reverses the order and doubles each one up, and when it hits an instance where there is 3 or more sKey's it goes a bit crazy :\
Anyone have any ideas, or can point me in the right direction?
If you're trying to use the MIN(skey) as your Master, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(skey) minskey
from mytable
group by pID
) p2 on p.pid = p2.pid and p.skey = p2.minskey
join mytable p3 on p.pid = p3.pid and p.skey != p3.skey
SQL Fiddle Demo
This produces slightly different results than yours above.
If your desired results are to use the first skey that shows up, then I'd recommend adding an Identity/AutoNumber column to your table just to seed from. You can't guarantee the order of the results without that column. So assuming you were to add such a column, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(id) minId
from mytable
group by pID
) p2 on p.id = p2.minId
join mytable p3 on p.pid = p3.pid and p.id <> p3.id
order by p.pid, p3.id
SQL Fiddle Demo With AutoNumber