Conditional join based on row value - sql

I have department mapping table where I have specific status for specific department but different status for all the rest departments that are not in department table.
dep_table:
country
department
status
FIN
D1
C
FIN
D2
C
FIN
**
O
SWE
D1
C
act_table:
country
department
amt
FIN
D1
16
FIN
D3
45
SWE
D1
13
expected result:
country
department
amt
status
FIN
D1
16
C
FIN
D3
45
O
SWE
D1
13
C
I have this but it causes duplicated rows (because joins ** and also non-** rows):
SELECT t1.country, t1.department, t1.amt, t2.status
FROM act_table t1
LEFT OUTER JOIN dep_table t2
ON t1.country = t2.country
AND CASE WHEN t1.department = t2.department THEN 1 WHEN t2.department = '**' THEN 1 END = 1
(This is very simplified scenario - needs to be done in this manner.)

If I understand correctly, you want 'O' if any of the statuses are 'O'. If there are only two statuses, you can use a correlated subquery:
select a.*,
(select d.status
from dep_table d
where d.country = a.country
order by d.status desc
fetch first 1 row only
) as status
from act_table a;

I think two left joins make it more clear :
with
dep_table (country, department, status) as (
values
('FIN', 'D1', 'C'),
('FIN', 'D2', 'C'),
('FIN', '**', 'O'),
('SWE', 'D1', 'C')
),
act_table (country, department, amt) as (
values
('FIN', 'D2', 16),
('FIN', 'D3', 45),
('SWE', 'D1', 13)
)
select
act.country, act.department, act.amt, coalesce(specific.status, rest.status) status
from act_table act
left join dep_table specific using(country, department)
left join dep_table rest on specific.status is null and (rest.country, rest.department) = (act.country, '**')
order by country, department

Use olap function row_number to select first row
select country , department , amt , status
from
(
select a.country , a.department ,
a.amt , d.status ,
row_number() over( partition by a.country , a.department
order by case when d.department = '**' then 1 else 0 end ) as rn1
from dep_table d ,
act_table a
where d.country = a.country
and ( d.department = a.department or d.department = '**' )
) x
where rn1 = 1

Related

CTE Multiple joins

I have a query in oracle and i need to add 2 conditions .
I'm new to CTE.Please let me know where i can add the conditions
Query:
WITH cte1 AS
(
SELECT
CASE
WHEN a.firstname IS NOT NULL THEN 1
ELSE 0
END FN
, CASE
WHEN NVL(a.acc_no, b.acc_no) IN (1004, 1003, 1001, 1005, 1007, 1004) THEN 'newacc'
WHEN A.acc_no IN (1003, 1009, 1004) THEN 'newacc'
ELSE 'old ACCOUNT'
END old_or_new
, A.date_created
, A.acc_no
, A.country
, A.organization
FROM
company A
INNER JOIN contacts C
ON C.contactid = A.contact_id
LEFT OUTER JOIN org_contacts d
ON d.contact_id = A.contact_id
FULL OUTER JOIN
(
SELECT
*
FROM
business
WHERE
business_id = 1
AND business_agent = 'N'
) B
ON (
B.auth_id1 = A._auth_id1
AND b.acc_no = a.acc_no
AND b.bus_id = a.bus_id
)
)
SELECT
*
FROM
cte1 x
WHERE
date_created BETWEEN '08/05/2019' AND '12/12/2020'
AND country = 'uk';
2 conditions
where date_created BETWEEN '08/05/2019' and '12/12/2020'
and country='uk'
are not working properly which i have added.
Let me know where i can add this.
NOte: these 2 columns are of table company a
It took me so long to find out the culprit. Instead of A.auth_id1 You used A._auth_id1
Please try below query:
WITH cte1 as
( SELECT
CASE WHEN a.firstname IS NOT NULL THEN 1 ELSE 0 END FN,
CASE
WHEN NVL( a.acc_no, b.acc_no) IN ( 1004,
1003,
1001,
1005,
1007,
1004) THEN
'newacc'
WHEN a.acc_no IN ( 1003,
1009,
1004) THEN
'newacc'
ELSE
'old ACCOUNT'
END old_or_new,
a.date_created ,
a.acc_no,
a.country,
a.organization
FROM company a
INNER JOIN contacts c
ON c.contactid = a.contact_id
and a.date_created BETWEEN '08/05/2019' and '12/12/2020'
and a.country='uk'
LEFT OUTER JOIN org_contacts d
ON d.contact_id = a.contact_id
FULL OUTER JOIN ( SELECT *
FROM business
WHERE business_id = 1
AND business_agent = 'N') b
ON ( b.auth_id1 = a.auth_id1
AND b.acc_no = a.acc_no
AND b.bus_id = a.bus_id))
SELECT *
FROM cte1

Combining two columns based on match in other colums in two tables

I have two tables, each containing two identical columns and one column unique for that table. What I need to do is combine those tables, with combinations of those unique columns for each matching pair of identical columns as result. Example of what I mean:
ACC ACTION PRIORITY ACC ACTION TARGET
A 1 10 A 1 i
A 2 15 A 1 j
A 3 25 A 3 k
B 3 101 B NULL l
B 4 102 B 4 m
B 5 103 B 1 n
ACC and ACTION are columns in both tables. ORDER is unique for the left one, TARGET for the right one. I need to get combinations of ORDER and TARGET on rows where ACC and ACTION match - for example when ACC is A and ACTION is 1, PRIORITY is 10, and TARGET is I or j, therefore combinations would be "10 I" and "10 j".
Also, when ACTION is null in right table, there should be row with the top PRIORITY on that TARGET.
So, expected result:
PRIORITY TARGET
10 i
10 j
25 k
102 m
103 l
Any attempt to do a correct JOIN or so failed from my side.
What I tried:
INSERT INTO #RESULT(TARGET, PRIORITY)
SELECT R.TARGET, MAX(L.PRIORITY)
FROM LEFT_TABLE L INNER JOIN RIGHT_TABLE R
ON L.ACC=R.ACC AND (L.ACTION = R.ACTION OR R.ACTION IS NULL);
But it gives an error. Grouping by TARGET does not make the right output, though.
I used UNION to solve this
SELECT priority, t.target
FROM prio p
JOIN target t ON p.acc = t.acc AND t.action = p.action
UNION
SELECT priority, t.target
FROM prio p
JOIN target t ON p.acc = t.acc AND t.action is null
AND p.priority = (SELECT MAX(priority) FROM prio)
See if this works. I did not test it.
DECLARE #L TABLE(ACC NVARCHAR(10),Action INT,Priority INT)
INSERT #L (ACC,Action,Priority) VALUES ('A',1,10),('A',2,15),('A',3,25),('B',4,101),('B',5,102),('B',6,103)
DECLARE #R TABLE(ACC NVARCHAR(10),Action INT,Target NVARCHAR(10))
INSERT #R (ACC,Action,Target) VALUES ('A',1,'i'),('A',1,'j'),('A',3,'k'),('B',NULL,'l'),('B',4,'m'),('B',1,'n')
SELECT
Target = MAX(R.Target),
Priority = MAX(L.Priority)
FROM
#L L
INNER JOIN #R R ON R.ACC=L.Acc AND (R.ACTION=L.Action OR R.Action IS NULL)
GROUP BY
L.ACC,
L.Action
ORDER BY
MAX(L.Priority)
You can do it like this:
Sample data
create table a
(
acc nvarchar(50),Action1 int, priority1 int)
create table b (acc nvarchar(50),action1 int, target1 nvarchar(50)
)
insert into a
values
('A',1, 10 ),
('A',2, 15 ),
('A',3, 25 ),
('B',3, 101),
('B',4, 102),
('B',5, 103)
insert into dbo.b
values
('A',1,'i'),
('A',1,'j'),
('A',3,'k'),
('B',null,'l'),
('B',4,'m'),
('B',1,'n')
SQL
with data1 as (
select acc,case when action1 is null then maxaction1 else action1 end as action1,target1 from (
select * from dbo.b a
cross apply (select MAX(action1) as MaxAction1 from dbo.a b where a.acc = b.acc ) x
)z
)
select priority1,target1 from data1 a inner join dbo.a b on a.acc = b.acc and a.action1 = b.Action1
Update
Just saw that you wrote you want it on Priority. Then you can do it like this:
SQL Code Update
with data1 as (
select * from (
select y.acc,y.target1,COALESCE(y.action1,c.action1) as Action1 from (
select * from dbo.b a
cross apply (select MAX(priority1) as MaxP from dbo.a b where a.acc = b.acc ) x
)y inner join dbo.a c on c.priority1 = MaxP
)z
)
select priority1,target1 from data1 a inner join dbo.a b on a.acc = b.acc and a.action1 = b.Action1
Result
You can try this:
WITH
tTable1
AS ( SELECT ACC
, [ACTION]
, [PRIORITY]
FROM ( VALUES ('A', 1, 10 )
, ('A', 2, 15 )
, ('A', 3, 25 )
, ('B', 3, 101)
, ('B', 4, 102)
, ('B', 5, 103)
) tTable1(ACC, [ACTION], [PRIORITY])
)
, tTable2
AS ( SELECT ACC
, [ACTION]
, [TARGET]
FROM ( VALUES ('A', 1 , 'i')
, ('A', 1 , 'j')
, ('A', 3 , 'k')
, ('B', NULL, 'l')
, ('B', 4 , 'm')
, ('B', 1 , 'n')
) tTable1(ACC, [ACTION], [TARGET])
)
, tTable1Max
AS ( SELECT ACC
, [PRIORITY] = MAX([PRIORITY])
FROM tTable1
GROUP BY ACC
)
, tResult
AS ( SELECT [PRIORITY] = CASE WHEN tTable2.[ACTION] IS NOT NULL
THEN tTable1.[PRIORITY]
ELSE tTable1Max.[PRIORITY]
END
, tTable2.[TARGET]
FROM tTable2
LEFT JOIN tTable1 ON tTable1.ACC = tTable2.ACC
AND tTable1.[ACTION] = tTable2.[ACTION]
OUTER APPLY ( SELECT [PRIORITY]
FROM tTable1Max
WHERE tTable1Max.ACC = tTable2.ACC
) tTable1Max
)
SELECT *
FROM tResult
WHERE [PRIORITY] IS NOT NULL
ORDER BY [PRIORITY]

How to sum the value of 2 different SQL queries?

I'm kinda new to using SQL. I have two different queries and I need to add or sum the value of one of the column in each queries. Sample code and screenshot of the outcome are provided below:
WITH tbl AS
(
SELECT
y.Location,
IIF(Status = 'Completed', 1,0) as Completed,
IIF(Status = 'Pending', 1, 0) as Pending,
IIF(Status = 'Scheduled', 1, 0) as Scheduled,
IIF(Satisfied = 'Satisfied', 1 , 0 ) As Satisfied,
IIF(Attrition IN ('Red', 'Amber'),1,0) As Attrition
FROM
order x
LEFT JOIN
roster y ON x.customerID = y.cID
LEFT JOIN
tbl_calendar z ON (x.starttime between z.datestart AND z.dateend)
WHERE
y.LOCATION IS NOT NULL
AND y.Location <> 'Ireland'
AND z.month ='2'
AND z.week IN (SELECT * FROM dbo.split('1,2,3',','))
AND z.year = '2017'
)
SELECT
Location,
SUM(Completed) AS Completed,
SUM(Pending) AS Pending,
SUM(Scheduled) AS Scheduled,
SUM(Satisfied) as Satisfied,
SUM(Attrition) as Attrition
FROM
tbl
GROUP BY
Location
And here is the second query:
SELECT
y.location, count (*) as qc
FROM
customer_quality x
LEFT JOIN
roster y ON x.customerEID = y.cEID
LEFT JOIN
tbl_calendar z ON (x.DateTimeDelivered BETWEEN z.datestart AND z.dateend)
WHERE
y.location IS NOT NULL
AND x.status = '4'
AND z.month = '2'
AND z.week IN (SELECT * FROM dbo.split('1,2,3',','))
AND z.year = '2017'
GROUP BY
y.Location
What I'm going to need to do is to add the value of the total completed orders from query 1 to the total quality customer on my query 2.
For example:
If there are 208 completed customer in Lisbon it would up the other 4 quality customer, the total should be 212.
It would show like this:
Location Completed Pending Scheduled Satisfied Attrition
Kuala Lumpur 388 76 9 388 3
Lisbon 212 92 29 207 1
Manila 3535 97 167 662 24
Mumbai 538 50 54 2100 6
Warsaw 147 38 4 145 9
I don't have data to test, but this should get you started.
With tbl as
( SELECT y.Location,
IIF(Status = 'Completed', 1,0) as Completed,
IIF(Status = 'Pending', 1, 0) as Pending,
IIF(Status = 'Scheduled', 1, 0) as Scheduled,
IIF(Satisfied = 'Satisfied', 1 , 0 ) As Satisfied,
IIF(Attrition IN ('Red', 'Amber'),1,0) As Attrition
FROM order x
LEFT JOIN roster y ON x.customerID=y.cID
LEFT JOIN tbl_calendar z ON (x.starttime between z.datestart AND z.dateend)
WHERE y.LOCATION IS NOT NULL
AND y.Location <> 'Ireland'
AND z.month ='2'
AND z.week IN (select * from dbo.split('1,2,3',','))
AND z.year='2017'
)
SELECT Location,
SUM(Completed) AS Completed ,
SUM (Pending) AS Pending,
SUM(Scheduled) AS Scheduled,
SUM(Satisfied) as Satisfied,
SUM(Attrition) as Attrition
INTO #TABLE1
FROM tbl
GROUP BY Location
SELECT y.location, count (*) as qc
INTO #TABLE2
FROM customer_quality x
LEFT JOIN roster y ON x.customerEID = y.cEID
LEFT JOIN tbl_calendar z ON (x.DateTimeDelivered between z.datestart
AND z.dateend)
WHERE y.location is not null
AND x.status='4' AND z.month = '2'
AND z.week IN (select * FROM dbo.split('1,2,3',',')) AND z.year='2017'
GROUP by y.Location
SELECT t1.Location
, (t1.Completed + t2.qc) AS Completed
, t1.Pending
, t1.Scheduled
, t1.Satisfied
, t1.Attrition
FROM #TABLE1 t1
JOIN #TABLE2 t2 ON
t1.Location = t2.Location
DROP TABLE #TABLE1
DROP TABLE #TABLE2
Create 2 CTEs as described in https://msdn.microsoft.com/en-us/library/ms175972.aspx#C-Using-multiple-CTE-definitions-in-a-single-query and then join them together and perform the desired calculations in your SELECT final clause
Or you could store you results from the first query in a temporary table using
SELECT * INTO #temp1 FROM (
SELECT Location,
SUM(Completed) AS Completed ,
SUM (Pending) AS Pending,
SUM(Scheduled) AS Scheduled,
SUM(Satisfied) as Satisfied,
SUM(Attrition) as Attrition
FROM tbl
GROUP BY Location
)
and
SELECT * INTO #temp2 FROM (
SELECT y.location, count (*) as qc
FROM customer_quality x
LEFT JOIN roster y ON x.customerEID = y.cEID
LEFT JOIN tbl_calendar z ON (x.DateTimeDelivered between z.datestart AND z.dateend)
WHERE y.location is not null
AND x.status='4' AND z.month = '2'
AND z.week IN (select * FROM dbo.split('1,2,3',',')) AND z.year='2017'
GROUP by y.Location
)
in the end the summarizing query could be:
SELECT t1.location
, t1.COMPLETED + t2.cq AS Completed
, t1.Pending
, t1.Scheduled
, t1.Satisfied
, t1.Attrition
FROM #temp1 t1
JOIN #temp2 t2 on t1.location = t2.location
or take the approach of stringing the CTEs together.

How to get only one value when you are getting multiple values against key in SQL

I have a SQL query. Below is the query
select
ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and
bussinesskey in
(
...
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
order by name, id asc
When this query runs then I get the output like the following snapshot
You can see in the screen shot that I am getting 8 names of same type(Contracts). The last id of Contracts is 780697 which is the latest record that is added to database. Now i want that when my query runs then it gets only the latest record. Means instead of showing 8 name of Contarcts. Its only the show the latest one for each course name. Means for Contracts only record with ID 780697 is shown. If other courses has the same result then there latest Id record is shown only. How can I achieve this ?
Thanks
You can try following for achieving latest ID:-
select MAX(ID),
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and
bussinesskey in
(
...
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
group by [Name], [Description], [GUID], Bussinesskey
order by name, id asc
Here how I did this. I don't know how efficient this is but it's giving me what I am exactly wanting
select ID, [Name], [Description], [GUID], Bussinesskey from (
select row_number() over (partition by [Name] order by id desc) as row, t1.* from (
select
ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and bussinesskey in (
'PSTOAS0314001',
...
'RECEAL0510019'
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
)t1
) t
where t.row=1
order by t.name, t.id asc
Thanks
;with Course as
(
Select 50000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB1' BusinessKey
UNION
Select 60000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB2' BusinessKey
UNION
Select 70000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB3' BusinessKey
UNION
Select 80000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB4' BusinessKey
UNION
Select 90000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB5' BusinessKey
UNION
Select 40000 ID, 'NOT Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB1' BusinessKey
),
Course_Group AS
(
Select 50000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 60000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 70000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 80000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 90000 Course_ID, 2 COURSEGROUP_ID
UNION
Select 40000 Course_ID, 1 COURSEGROUP_ID
),
CourseGroup_CustomerEntitlement AS
(
Select 1 COURSEGROUP_ID, 1 CUSTOMERENTITLEMENT_ID
--UNION
--Select 2 COURSEGROUP_ID, 2 CUSTOMERENTITLEMENT_ID
--UNION
--Select 2 COURSEGROUP_ID, 4 CUSTOMERENTITLEMENT_ID
),
Course_CustomerEntitlement AS
(
Select 50000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 60000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 90000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 40000 Course_ID, 4 CUSTOMERENTITLEMENT_ID
),
CustomerEntitlement AS
(
Select 1 ID, 23753 Customer_ID, 'CourseGroup' ENROLLMENTTYPE
UNION
Select 2 ID, 7 Customer_ID, 'NOT COURSE GROUP' ENROLLMENTTYPE
UNION
Select 3 ID, 23753 Customer_ID, 'Course' ENROLLMENTTYPE
UNION
Select 4 ID, 7 Customer_ID, 'NOT COURSE' ENROLLMENTTYPE
),
CTE_base_data as (
SELECT
C.ID,
replace(replace(replace(replace(C.[Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace(C.[Description],',',''),'"','') [Description],
C.[GUID],
C.Businesskey
FROM Course C
JOIN Course_Group CG ON CG.Course_ID = C.ID
JOIN CourseGroup_CustomerEntitlement CG_CE ON CG_CE.COURSEGROUP_ID = CG.COURSEGROUP_ID
JOIN CustomerEntitlement CE_GROUP ON CE_GROUP.ID = CG_CE.CUSTOMERENTITLEMENT_ID
AND CE_GROUP.ENROLLMENTTYPE = 'CourseGroup'
WHERE
CE_GROUP.Customer_ID = 23753
UNION
SELECT
C.ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Businesskey
FROM Course c
JOIN Course_CustomerEntitlement CCE ON CCE.Course_ID = C.ID
JOIN CustomerEntitlement CE_COURSE ON CE_COURSE.ID = CCE.CUSTOMERENTITLEMENT_ID
AND CE_COURSE.ENROLLMENTTYPE = 'COURSE'
WHERE
CE_COURSE.Customer_ID = 23753
--and COURSESTATUS = 'Published'
--and RETIREDTF = 0
--and businesskey in
-- (
-- ...
-- )
),
CTE_max_data as (
Select name, max(ID) ID
from CTE_base_data
group by name
)
Select Data.*
from CTE_base_data Data
JOIN CTE_max_data Filter
ON Data.ID = Filter.ID
AND Data.Name = Filter.Name
order by name, id asc
This yields:
ID Name Description GUID Businesskey
90000 Contracts ARB5
40000 NOT Contracts ARB1
Please advise where my data assumptions fall flat.

SQL Query return latest date with additional information from tables

I have 5 tables and columns pertinent to this query:
Dogs (ID, CallName, Color, Sex, Chipnumber, BreedID)
Breed (ID, Name)
Status (ID, Status, OwnedOnPremises)
DogsStatus (ID, DogsID, StatusID, StatusDate, Note, ContactsID)
Contacts (ID, Name)
I am wanting a result of all dogs and their LATEST status. For a test I am using the following records:
Dogs (251, Tank, Fawn, M, 14410784, 23) (266, Bonnie, Brindle, 14964070, 23)
Breed (23, Mastiff)
Status (3, Sold) (4, Given Away) (7, Purchased) (9, Returned)
DogsStatus (29, 251, 3, 2013-10-12, 5) (39, 251, 9, 2013-11-10, 17) (146, 251, 4, 2014-01-10, 7) (40, 266, 7, 2013-10-30, 1)
Contacts (1, Person1) (5, Person5) (7, Person7) (17, Person17)
So far I have:
SELECT
d.CallName, b.Name AS 'Breed', d.Color, d.Sex, d.ChipNumber
FROM
Dogs d
JOIN
(SELECT
DogsID, MAX(StatusDate) as MaxStatusDate
FROM DogsStatus
GROUP BY DogsID) mds ON mds.DogsID = d.ID
JOIN
Breeds b ON b.ID = d.BreedID
This will return 2 unique records (1 for Tank and 1 for Bonnie), but whenever I try to get any other of the DogsStatus and/or Status info, I either return only one dog record, or all 3 of Tanks DogsStatus records.
Thanks in advance.
You'll need to join your MaxStatusDate to the DogsStatus table. That way you will only get the most recent status, in the case where you have multiple statuses.
Something like
SELECT
d.CallName, b.Name AS 'Breed', d.Color, d.Sex, d.ChipNumber
FROM
Dogs d
innner join DogsStatus ds
ON d.dogsid = ds.dogs_id
JOIN
(SELECT
DogsID, MAX(StatusDate) as MaxStatusDate
FROM DogsStatus
GROUP BY DogsID) mds ON mds.DogsID = d.ID
JOIN
Breeds b ON b.ID = d.BreedID
AND mds.maxstatusdate = ds.statusdate
Something along those lines.
You're close. You just need to go back to the DogStatus table to get that full record. Note that I prefer CTEs for this, but your existing derived table (subquery) approach works just fine, too:
With StatusDates As
(
SELECT
DogsID, MAX(StatusDate) as StatusDate
FROM DogsStatus
GROUP BY DogsID
), CurrentStatus As
(
SELECT ds.*
FROM DogStatus ds
INNER JOIN StatusDates sd ON sd.DogsID = ds.DogsID AND ds.StatusDate = sd.StatusDate
)
SELECT d.Name, b.Name As Breed, d.Color, d.Sex, d.ChipNumber
, s.Status, cs.StatusDate, c.Name As ContactName
FROM Dogs d
INNER JOIN CurrentStatus cs ON cs.DogsID = d.ID
INNER JOIN Breed b on b.ID = d.BreedID
INNER JOIN Status s on s.ID = cs.StatusID
INNER JOIN Contact c on c.ID = cs.ContactID
You may want to use a LEFT join for some of those, and then change the select list to use coalesce() expressions to clean up the NULLs.
It would be something like this, I'm certain you'll be able to adapt it to your needs:
;with x as (
select *, row_number() over(partition by d.DogsId order by StatusDate desc) as rn
from Dogs d
inner join DogsStatus on d.DogsId = ds.DogsId
)
select *
from x
where rn = 1