comparing fields in 2 different tables using SQL - sql

I would like to compare if the address fields in contact table are different to that of the delivery table.
SELECT contactID, addressline1
FROM contact
where contactID = '0018319'
Below is the delivery table which contains the old details.
SELECT contactID, addressline1
FROM delivery
where contactID = '0018319'

SELECT contactID, d.addressline1, c.addressline1
FROM delivery d
INNER JOIN contact c on d.contactID = c.contactID
where d.addressline1 != c.addressline1

If you want to return a flag, then you would use case in the select statement:
select contactId,
(case when d.addressline1 = c.addressline1 or d.addressline1 is null and c.addressline1 is null
then 'SAME'
else 'DIFFERENT'
end) as SameOrDifferent
from contact c join
delivery d
on c.contactId = d.contactId
where contactId = '0018319';
This is going to compare each address in the two tables.
If you want to know if all are the same, then the query is more complicated. The idea is to do a full outer join between the two table (for the given contractid) on addressline1. If all the addresslines match, then the full outer join will never produce NULL values. If any are missing (on either side), then there will be NULL values.
select coalesce(c.contactId, d.contactId) as contactId,
(case when sum(case when c.addressline1 is null or d.addressline1 is null
then 1
else 0
end) = 0
then 'SAME'
else 'DIFFERENT'
end) as SameOrDifferent
from (select c.* from contact c where c.contactId = '0018319') c full outer join
(select d.* from delivery d where d.contactId = '0018319') d
on c.addressline1 = d.addressline1 and
c.contactId = d.contactId -- not actually necessary but useful for multiple contacts
group by coalesce(c.contactId, d.contactId)

Related

Select an ID where there is only one row and that row is a specific value

I have this query. There's a lot of joins because I am checking if an ID is linked to any of those tables.
Currently, this query shows me any ID's that are not linked to any of those tables. I would like to add to it so that it also shows any IDs that are linked to the d table, but only if there is only 1 row in the D table and the type in the D field is 'member'.
SELECT
c.ID,
c.location,
c.pb,
c.name,
c.surname
FROM c
LEFT JOIN l on c.rowno = l.rowno
LEFT JOIN d on c.rowno = d.rowno
LEFT JOIN t on c.rowno = t.rowno
LEFT JOIN cj ON (c.rowno = cj.rowno OR c.rowno = cj.rowno2)
LEFT JOIN dj ON c.rowno = d.rowno
LEFT JOIN lg ON c.rowno = lg.rowno
LEFT JOIN tj ON c.rowno = tj.rowno
WHERE
c.status != 'closed'
AND l.rowno IS NULL
AND d.rowno IS NULL
AND t.rowno IS NULL
AND cj.rowno IS NULL
AND dj.rowno IS NULL
AND lg.rowno IS NULL
AND tj.rowno IS NULL
My first thought is to just add
WHERE D.type = 'member'
But that gives me all IDs that have a row with D.type = member (they could have 10 rows with all different types, but as long as 1 of those has type = member it shows up). I want to see ID's that ONLY have d.type = member
I'm sorry if I'm wording this badly, I'm having trouble getting this straight in my head. Any help is appreciated!
I would use exists for all conditions except the one on the D table:
SELECT c.*
FROM c JOIN
(SELECT d.rownum, COUNT(*) as cnt,
SUM(CASE WHEN d.type = 'Member' THEN 1 ELSE 0 END) as num_members
FROM t
GROUP BY d.rownum
) d
ON c.rownum = d.rownum
WHERE c.status <> 'closed' AND
NOT EXISTS (SELECT 1 FROM t WHERE c.rowno = t.rowno) AND
NOT EXISTS (SELECT 1 FROM l WHERE c.rowno = l.rowno) AND
. . .
I find NOT EXISTS is easier to follow logically. I don't think there is a big performance difference between the two methods in SQL Server.

SQL results in one row

I have following statement:
SELECT
Person.PersonID, Person.PersonName, Person.Surname,
Address.Street, Address.PostCode,
(SELECT Phones.Num
WHERE (Phones.CommunicationTypeId = '78')) AS email,
(SELECT Phones.Num
WHERE (Phones.CommunicationTypeId = '83')) AS mobile,
(SELECT Phones.Num
WHERE (Phones.CommunicationTypeId = '88')) AS phone
FROM
Address
RIGHT OUTER JOIN
Person ON Address.ObjectId = Person.PersonID
RIGHT OUTER JOIN
Phones ON Person.PersonID = Phones.ObjectID
Now results shows separate rows, while I want to have it in one row:
How to consolidate it into just one row?
Looks like your person has more than one corresponding phone records (I guess 2 records with different types.
SELECT
ObjectID,
MAX(CASE WHEN CommunicationTypeId = '78' THEN Num ELSE null END) as email,
MAX(CASE WHEN CommunicationTypeId = '83' THEN Num ELSE null END) as mobile,
MAX(CASE WHEN CommunicationTypeId = '88' THEN Num ELSE null END) as phone
FROM Phones
GROUP BY ObjectID
The select above returns 3 columns for each person and you can use it in the main query
SELECT
Person.PersonID, Person.PersonName, Person.Surname,
Address.Street, Address.PostCode,
Phones.email, Phones mobile, Phones.phone
FROM
Address
RIGHT OUTER JOIN
Person ON Address.ObjectId = Person.PersonID
RIGHT OUTER JOIN
(sub query above) Phones ON Person.PersonID = Phones.ObjectID

Condensing duplicate data while maintaining multiple entries per client

I apologize if the title is not descriptive enough. I am having a hard time describing what I am looking for.
I understand this is normally done on the front end but a client is requesting to have this data displayed in this way. this should show a single column with client information (lastname, firstname) and any/all booked appointments. Since there may be more than one appointment per client duplicate data will be displayed along each line. That will look like this:
lastName | firstName | apptDate | myStartTime | myEndTime
smith..............| john................| 4/7/2016........| 7:00.........................| 8:00
smith..............| john................| 4/9/2016........| 6:00.........................| 7:00
smith..............| john................| 4/14/2016......| 10:00.......................| 11:00
arnold.............| williams..........| 4/10/2016......| 7:00.........................| 11:00
arnold.............| williams..........| 4/11/2016......| 8:00.........................| 12:00
but I would like that to be displayed as:
smith..............| john................| 4/7/2016........| 7:00.........................| 8:00
................................................| 4/9/2016........| 6:00.........................| 7:00
................................................| 4/14/2016......| 10:00.......................| 11:00
arnold..............| williams.........| 4/10/2016.......| 7:00.........................| 11:00
................................................| 4/11/2016.......| 8:00.........................| 12:00
This is what I am currently working with:
SELECT
CASE
WHEN cli.rownum = 1 THEN cli.clientID
END AS 'clientID'
,CASE
WHEN cli.rownum = 1 THEN cli.lastName
END AS 'lastName'
,CASE
WHEN cli.rownum = 1 THEN cli.firstName
END AS 'firstName'
,CASE
WHEN cli.rownum = 1 THEN cli.homePhone
END AS 'home'
,CASE
WHEN cli.rownum = 1 THEN cli.cellPhone
END AS 'cell'
,info.*
,CASE
WHEN cli.rownum = 1 THEN cli.staffAlertMsg
END AS 'alert'
,cli.notes AS 'notes'
,CONVERT(varchar(10),cli.classDate,101) AS 'date'
,cli.myStartTime AS 'start'
,cli.myEndTime AS 'end'
,cli.typeName AS 'appointment'
FROM
(SELECT
c.clientID
,c.lastName
,c.firstName
,c.homePhone
,c.cellPhone
,info.*
,r.notes
,c.staffAlertMsg
,r.ClassDate
,r.myStartTime
,r.myEndTime
,vt.TypeName
,ROW_NUMBER()
OVER(PARTITION BY c.clientID ORDER BY c.clientID) AS 'rownum'
FROM clients c
LEFT OUTER JOIN tblReservation r
ON c.clientID = r.clientID
LEFT OUTER JOIN tblVisitTypes vt
ON vt.TypeID = r.visitType
OUTER APPLY
(SELECT
max(CASE
WHEN civ.clientIndexID = 4
THEN civ.clientIndexValueName
END) AS 'priority'
,max(CASE
WHEN civ.clientIndexID = 5
THEN civ.clientIndexValueName
END) AS 'lang'
,max(CASE
WHEN civ.clientIndexID = 17
THEN civ.clientIndexValueName
END) AS 'inter'
,max(CASE
WHEN ccf.name LIKE 'prac'
THEN ccv.TextVal
END) AS 'prac'
,max(CASE
WHEN st.TypeID = 100000001 THEN st.typeName
END) AS 'ride?'
,max(CASE
WHEN st.typeID = 100000006 THEN st.typeName
END) AS 'l?'
FROM tblClientCustomValues ccv
INNER JOIN tblClientCustomFields ccf
ON ccv.ID = ccf.ID
INNER JOIN tblClientIndexData cid
ON ccv.clientID = cid.clientID
INNER JOIN tblClientIndexValue civ
ON cid.clientIndexValueID = civ.clientIndexValueID
LEFT JOIN [type details] td
ON ccv.clientID = td.clientID
LEFT JOIN [student types] st
ON td.typeID = st.typeID
WHERE c.clientID = ccv.clientID
) info
) cli
WHERE cli.clientID != '-2'
AND cli.clientID != '0'
AND cli.clientID != '1'
AND (cli.classDate >= '4/1/2016'
AND cli.classDate <= '4/30/2016')
Assuming you want to only return the name for the first row of each client then this should work (also assuming a primary key column of ID on the clients table):
SELECT CASE WHEN cli.rownum = 1 THEN cli.lastName END AS lastName
,CASE WHEN cli.rownum = 1 THEN cli.firstName END AS firstName
,CONVERT(varchar(10),cli.apptDate,101) AS 'apptDate'
,cli.myStartTime
,cli.myEndTime
FROM
(SELECT c.ID
,c.lastName
,c.firstName
,r.apptDate
,r.myStartTime
,r.myEndTime
,ROW_NUMBER() OVER (PARTITION BY c.ID ORDER BY c.ID, r.apptDate, r.myStartTime) as rownum
FROM clients c
LEFT OUTER JOIN tblReservation r
ON c.clientID = r.clientID
LEFT OUTER JOIN tblVisitTypes vt
ON vt.TypeID = r.VisitType)
cli
ORDER BY cli.ID, cli.rownum
I have made both the join LEFT OUTER JOINS as your second INNER JOIN would have made the first join an INNER, which I assume is not what you wanted.

Selecting columns based on a case SQL

I'm wondering how I can return specific results depending on my first selected statement. Basically I have two IDs. CustBillToID and CustShipToID. If CustShipToID is not null I want to select that and all the records that are joined to it. If it is null default to the CustBillToID and all the results that are joined to that.
Here is my SQL that obviously doesn't work. I should mention I tried to do a sub query in the conditional, but since it returns multiple results it won't work. I am using SQL Server 2012.
SELECT CASE WHEN cp.CustShipToID IS NOT NULL
THEN
cy.CustDesc,
cy.Address1,
cy.Address2,
cy.City,
cy.State,
cy.ZIP,
cy.Phone
ELSE
c.CustDesc,
c.Address1,
c.Address2,
c.City,
c.State,
c.ZIP,
c.Phone
END
LoadID,
cp.CustPOID,
cp.POBillToRef,
cp.POShipToRef,
cp.CustBillToID,
cp.CustShipToID,
cp.ArrivalDate,
cp.LoadDate,
cp.StopNum,
cp.ConfNum,
cp.EVNum,
cp.ApptNum,
ld.CarrId,
ld.Temperature,
cr.CarrDesc
FROM [Sales].[dbo].[CustPO] AS cp
LEFT OUTER JOIN Load AS ld
ON cp.LoadID = ld.LoadID
LEFT OUTER JOIN Carrier AS cr
ON ld.CarrId = cr.CarrId
LEFT OUTER JOIN Customer AS c
ON c.CustId = cp.CustBillToID
WHERE CustPOID=5213
Any ideas?
Also my current SQL is below, I do a conditional to determine if it's set. I'd rather do it in SQL if possible.
SELECT cp.LoadID,
cp.CustPOID,
cp.POBillToRef,
cp.POShipToRef,
cp.CustBillToID,
cp.CustShipToID,
cp.ArrivalDate,
cp.LoadDate,
cp.StopNum,
cp.ConfNum,
cp.EVNum,
cp.ApptNum,
ld.CarrId,
ld.Temperature,
cr.CarrDesc,
c.CustDesc as CustBillToDesc,
c.Address1 as CustBillAddress1,
c.Address2 as CustBillAddress2,
c.City as CustBillCity,
c.State as CustBillState,
c.ZIP as CustBillZIP,
c.Phone as CustBillPhone,
cy.CustDesc as CustShipToDesc,
cy.Address1 as CustShipAddress1,
cy.Address2 as CustShipAddress2,
cy.City as CustShipCity,
cy.State as CustShipState,
cy.ZIP as CustShipZIP,
cy.Phone as CustShipPhone
FROM [Sales].[dbo].[CustPO] as cp
left outer join Load as ld
on cp.LoadID = ld.LoadID
left outer join Carrier as cr
on ld.CarrId = cr.CarrId
left outer join Customer as c
on c.CustId = cp.CustBillToID
left outer join Customer as cy
on cy.CustId = cp.CustShipToID
WHERE CustPOID=?
You need a separate case for each column:
SELECT (CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.CustDesc ELSE c.CustDesc END) as CustDesc,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Address1 ELSE c.Address1 END) as Address1,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Address2 ELSE c.Address2 END) as Address2,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.City ELSE c.City END) as City,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.State ELSE c.State END) as State,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.ZIP ELSE c.ZIP END) as ZIP,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Phone ELSE c.Phone END) as Phone,
. . .
For this, you basically want to build a string that is your SQL and then execute the string...look # the answer to this one ::
SQL conditional SELECT
Did you try coalesce(CustShipToID,CustBillToID ) ?
...
FROM [Sales].[dbo].[CustPO] as cp
left outer join Load as ld
on cp.LoadID = ld.LoadID
left outer join Carrier as cr
on ld.CarrId = cr.CarrId
inner join Customer as c
on c.CustId = coalesce(cp.CustShipToID,cp.CustBillToID )
...

SQL-subquery workaround to join based on alias

Attempted Subquery using alias
SELECT
*,
IQ.EndPart,
IQ.QtyToShip
FROM
parts p
INNER JOIN (
select
*,
(case when c.kitno is null then l.partno else c.partno end) as [EndPart],
(case when c.kitno is null then l.TotalQuantity else c.reqqty end) as [QtyToShip]
FROM
shipments s
INNER JOIN shipments_li l ON s.ShipmentNo = l.ShipmentNo
LEFT JOIN ProductConfiguration c ON l.PartNo = c.KitNo WHERE s.Status='N' and year(s.OrderDate)>2007
) IQ ON p.partno = IQ.EndPart
Looking for a way to join the parts table to my query below, using the part # which is aliased as EndPart. If there is another way to acheive the results of taking two columns and combining them instead of case and an alias that would be a great alternative as well. All my searches of other individuals quest to achieve the same have yielded the result you cannot perform a join based on alias because the results have not been determined at that point, recommending a subquery as a workaround. I'm just not sure how to acheive working results. The above query was what I attempted to get working. Any help appreciated. Thanks in advance.
Original Query
SELECT
*,
(case when c.kitno is null then l.partno else c.partno end) as [EndPart],
(case when c.kitno is null then l.TotalQuantity else c.reqqty end) as [QtyToShip]
FROM
shipments s
INNER JOIN shipments_li l ON s.ShipmentNo = l.ShipmentNo
LEFT JOIN ProductConfiguration c ON l.PartNo = c.KitNo
WHERE
s.Status='N'
and year(s.OrderDate)>2007
order by s.shipmentno
More proper way
--- CREATE TempTable
DECLARE #tblTemp AS TABLE (EndPart INT,
QtyToShip INT)
INSERT INTO #tblTemp (EndPart, QtyToShip)
SELECT
(CASE WHEN c.kitno IS NULL
THEN l.partno ELSE c.partno END) AS [EndPart],
(CASE WHEN c.kitno IS NULL
THEN l.TotalQuantity
ELSE c.reqqty END) AS [QtyToShip]
FROM dbo.Shipments s WITH(NOLOCK)
INNER JOIN shipments_li l WITH(NOLOCK) ON s.ShipmentNo = l.ShipmentNo
LEFT JOIN ProductConfiguration c WITH(NOLOCK) ON l.PartNo = c.KitNo
WHERE s.Status='N' AND YEAR(s.OrderDate)>2007
SELECT
p.*,
tmp.EndPart,
tmp.QtyToShip
FROM dbo.parts p WITH(NOLOCK)
INNER JOIN #tblTemp tmp ON p.partno = tmp.EndPart