SQL subquery to join the most recent plan for a client - sql

In MS Access 365, I have two tables (TClients & TPlans) that I am trying to combine into a single Query (QClientsExtended). Each client could have many or no associated entries on the TPlan list. In my final query, I would like it to list every client regardless of wether or not they have a plan, and give me the date and the details of the most recent plan, if there is one.
I've read all the relevant W3C reference pages, and looked at so many possible solutions, and i've struggled to turn them into something that works for this. It feels like it should be SO simple, I appreciate I'm probably missing a fundamental aspect of SQL coding.
TClients
ClientID ClientFullName ExternalAppts
1 Testy McTestFace 1
2 Clemence Closed 0
3 Nancy New Ref 3
4 Juan One Appt 0
TPlans
PlanID ClientID PlanDetails PlanDate
1 3 Plan 1 05-Dec-22
2 3 Plan 2 10-Dec-22
3 1 plan 10-Dec-22
4 4 nil 05-Dec-22
Qclients Extended
ClientID ClientFullName PlanDetails PlanDate ExternalAppts
1 Testy McTestFace Plan 2 10-Dec-22 1
2 Clemence Closed 0
3 Nancy New Ref plan 10-Dec-22 3
4 Juan One Appt nil 05-Dec-22 0

I've found a solution, but it feels incredibly clunky. I have made two Queries, one to find the most recent date for each client, and the second to Left Join this with the Client Table. I'm sure this should be doable in a single query, but maybe it can't be done in Access. Here are my two Queries:
QlastPlan
SELECT t1.*
FROM TPlans AS t1
INNER JOIN (
SELECT [ClientID],
MAX(PlanDate) AS LastPlan
FROM TPlans
GROUP BY [ClientID])
AS t2 ON (t1.[PlanDate] = t2.LastPlan) AND (t1.[ClientID] = t2.[ClientID]);
QClients
SELECT
TC.*,
QLP.PlanDetails,
QLP.PlanDate,
FROM TClients TC
LEFT JOIN QlastPlan QLP on TC.ClientID = QLP.ClientID;
So perhaps there's another option someone can suggest, but this is what I will run with for now.

Try with a Left Join:
SELECT
TClients.ClientID,
TClients.ClientFullName,
TPlans.PlanDetails,
TPlans.PlanDate,
TClients.ExternalAppts
FROM
TClients
LEFT JOIN
TPlans ON TClients.ClientID = TPlans.ClientID
GROUP BY
TClients.ClientID,
TClients.ClientFullName,
TPlans.PlanDetails,
TPlans.PlanDate,
TClients.ExternalAppts
HAVING
TPlans.PlanDate=
(Select Max(PlanDate) From [TPlans] As T Where T.ClientID = TClients.[ClientID])
OR
TPlans.PlanDate Is Null

Related

SQL Query with 2 joins and different values

I'm quite the beginner so I suppose some of you would have an easy time on my task but I need some help:
I have 3 DBs. dbo_A_Personal, dbo_Z_Ferien and dbo_Z_ERFASSUNG
A_Pers has a Pers_ID (LPE_ID) that I can use to join Z_Ferien and Z_ERFASSUNG on.
In Z_Ferien I have 4 rows with that pers_ID and in Z_ERFASSUNG 96.
What I need is a result that has columns that are basically like that:
PersID
Erf
Fer
1224
5
0
1234
4
0
1234
6
0
1234
0
6
so far I have this:
SELECT dbo_A_PERSONAL.LPE_ID, dbo_Z_Ferien.ZFE_TAGE, dbo_Z_ERFASSUNG.ZER_Std100
FROM dbo_A_PERSONAL
INNER JOIN dbo_Z_Ferien ON dbo_A_PERSONAL.LPE_ID = dbo_Z_Ferien.ZFE_LPE_ID
INNER JOIN dbo_Z_ERFASSUNG ON dbo_A_PERSONAL.LPE_ID = dbo_Z_ERFASSUNG.ZER_LPE
WHERE dbo_A_PERSONAL.LPE_ID=804 AND dbo_Z_ERFASSUNG.ZER_EIGENSCH = 3;
I need that so I can sum up the value I need from Z_ERFASSUNG and Z_Ferien but I don't know how to make it so each value is only "printed" once.
I hope I explained it well enough so you guys can help me out.
If I understand correctly an aggerate function is what you need here.
I added a sum function of both dbo_Z_Ferien & dbo_Z_ERFASSUNG, as well as adding a group by statement for LPE_ID. Which tells SQL to partition the sum only on LPE_ID
SELECT dbo_A_PERSONAL.LPE_ID, sum(dbo_Z_Ferien.ZFE_TAGE), sum(dbo_Z_ERFASSUNG.ZER_Std100)
FROM dbo_A_PERSONAL
INNER JOIN dbo_Z_Ferien ON dbo_A_PERSONAL.LPE_ID = dbo_Z_Ferien.ZFE_LPE_ID
INNER JOIN dbo_Z_ERFASSUNG ON dbo_A_PERSONAL.LPE_ID = dbo_Z_ERFASSUNG.ZER_LPE
WHERE dbo_A_PERSONAL.LPE_ID=804 AND dbo_Z_ERFASSUNG.ZER_EIGENSCH = 3
GROUP BY dbo_A_PERSONAL

MS access join two tables, get unique rows

This is a modification to a previous question original answer , I hope the proper thing to do is start a new thread.
I have a table called Parts, PartRefID is the PK
PartRefID PartDefID AssemblyID
1 2 c63df10b-8250-4aa5-9889-9e8046331dbf
11 1 db51f4a8-3ffa-41f7-81c1-a9accbbb299a
67 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
77 5 38fa8b7a-2945-4546-8eab-7865a1e515b2
133 2 c63df10b-8250-4aa5-9889-9e8046331dbf
134 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
I need to extract rows with a unique AssemblyID. This was answered by GMB with the following sql:
select *
from parts as p
where [PartRefID] = (
select max(p1.[PartRefID])
from parts as p1
where p1.[AssemblyID] = p.[AssemblyID] and p1.[PartDefID] = 2
)
which worked beautifully. However requirements have changed and I must ignore the PartDefID field and there could also be AssemblyID's which represent parts I do not want.
The AssemblyID's shown in the above table represent an electrical connector part.
Electrical connector parts will ALWAYS have a Partclass of 1 which is defined in another table called PartDefinitions shown here:
PartDefID PartClass PartNumber
1 1 MS27467T23F55P
2 1 330-00186-09
3 2 336-00024-00
4 2 336-00022-00
5 1 MS27468T23F55S
6 1 330-00184-09
with my limited sql knowledge I decided a join was necessary and came up with the following code:
SELECT Parts.*, PartDefinitions.PartClass
From PartDefinitions
INNER Join Parts
On PartDefinitions.PartDefID = Parts.PartDefID
Where (((PartDefinitions.PartClass) = 1))
this gets me close, it produces all the parts in the parts table which are connectors. However there are some duplicate AssemblyID's.
what I need is to produce the following:
PartRefID PartDefID AssemblyID
1 2 c63df10b-8250-4aa5-9889-9e8046331dbf
11 1 db51f4a8-3ffa-41f7-81c1-a9accbbb299a
67 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
77 5 38fa8b7a-2945-4546-8eab-7865a1e515b2
my apologies if I have not made a clear and concise question
thanks for any help
and thanks again GMB
If I understand correctly, you want to filter by the PartClassId in both the subquery and the outer query:
select p.*, pd.PartClass
From Parts as p inner join
PartDefinitions as pd
on pd.PartDefID = p.PartDefID
where pd.PartClassId = 1 and
p.pPartRefID = (select max(p2.pPartRefID)
from parts as p2 inner join
PartDefinitions as pd2
on pd2.PartDefID = pd.PartDefID
where p2.AssemblyID = p.AssemblyID and
p2.PartClassId = 1
)

Access SQL Syntax for Cross-Table Count

I have what may be a simple SQL syntax question but I've been scratching my head over it for weeks now and it's abstract enough that I'm having trouble hunting down the correct search in Google.
Let us assume that I have three tables: Users and Bookings:
Users:
UserID Name
1 Adam
2 Bob
3 Charlie
Bookings:
BookingID UserID MeetingID
1 1 1
2 2 1
3 2 2
4 3 2
The query that I'm looking to create will tell me how many other users each user has shared a meeting ID with. In my example:
Output:
UserID Co-Meeters
1 1
2 2
3 1
As in the example, users 1 and 3 only had one co-meeter (in this case "2") and user 2 had two co-meeters (1 and 3).
I'm sorry if my description isn't terribly clear, but I'm trying to strip out the needless complication from other intersecting tables and fields that don't really affect the syntax I'm looking for. My initial thought was to use "Group By", but since Bookings is a many-to-many (in terms of the fields I'm looking at) I can't make the logic work.
Any and all help is appreciated.
I think this should do the trick:
select u.userid, iif(isnull(x.others), 0, x.others) as [Co-Meeters]
from users u
left join bookings b on u.userid = b.userid
left join (
select meetingid, count(*) as others from bookings where userid <> u.userid
) x on b.meetingid = x.meetingid
order by 1

Why does this query return "incorrect" results?

I have 3 tables:
'CouponType' table:
AutoID Code Name
1 CouT001 SunCoupon
2 CouT002 GdFriCoupon
3 CouT003 1for1Coupon
'CouponIssued' table:
AutoID CouponNo CouponType_AutoID
1 Co001 1
2 Co002 1
3 Co003 1
4 Co004 2
5 Co005 2
6 Co006 2
'CouponUsed' table:
AutoID Coupon_AutoID
1 2
2 3
3 5
I am trying to join 3 tables together using this query below but apparently I am not getting right values for CouponIssued column:
select CouponType.AutoID, Code, Name, Count(CouponIssued.CouponType_AutoID), count(CouponUsed.Coupon_AutoID)
from (CouponType left join CouponIssued
on (CouponType.AutoID = CouponIssued.CouponType_AutoID))
left join CouponUsed
on (couponUsed.Coupon_AutoID = CouponIssued.AutoID)
group by CouponType.AutoID, code, name
order by code
The expected result should be like:
**Auto ID Code Name Issued used**
1 CouT001 SunCoupon 3 2
2 CouT002 GdFriCoupon 3 1
3 CouT003 1for1Coupon 0 0
Thanks!
SELECT t.AutoID
,t.Code
,t.Name
,count(i.CouponType_AutoID) AS issued
,count(u.Coupon_AutoID) AS used
FROM CouponType t
LEFT JOIN CouponIssued i ON i.CouponType_AutoID = t.AutoID
LEFT JOIN CouponUsed u ON u.Coupon_AutoID = i.AutoID
GROUP BY 1,2,3;
You might consider using less confusing names for your table columns. I have made very good experiences with using the same name for the same data across tables (as far as sensible).
In your example, AutoID is used for three different columns, two of which appear a second time in another table under a different name. This would still make sense if Coupon_AutoID was named CouponIssued_AutoID instead.
change count(Coupon.CouponType_AutoID) to count(CouponIssued.CouponType_AutoID) and count(Coupon.Coupon_AutoID) to count(CouponUsed.Coupon_AutoID)

Problem with SQL Join

I have two tables, tblEntities and tblScheduling.
tblEntities:
EntityID ShortName Active
1 Dirtville 1
2 Goldtown 1
3 Blackston 0
4 Cornfelt 1
5 Vick 1
tblScheduling:
ScheduleID EntityID SchedulingYearID
1 1 20
2 1 21
3 2 20
4 3 19
5 5 20
I need a query that will show ALL ACTIVE Entities and their schedule information for a particular ScheduleYearID.
Output should look like (the desired SchedulingYearID in this case is 20):
EntityID ScheduleID
1 1
2 3
4 NULL
5 5
The query that I have written so far is:
SELECT tblEntities.EntityID, tblEntities.ShortName, tblScheduling.ScheduleID
FROM tblScheduling RIGHT OUTER JOIN
tblEntities ON tblScheduling.EntityID = tblEntities.EntityID
WHERE (tblScheduling.SchedulingYearID = #SchedulingYearID)
AND (tblEntities.Active = 1)
ORDER BY tblEntities.EntityID
My problem is that using this query it will not include active entities without schedule information (such as EntityID 4 in the example above). I can write the query to display all active entities and their schedule status fine, but once I start limiting it via the SchedulingYearID I lose those particular entities.
Are there any solutions that I am obviously missing without having to resort to subqueries, cursors, etc.? If not it's not a big deal, I just feel like I am missing something simple here.
Try this... Join conditions are evaluated to produce the intermediate Join result set, and then, (for an outer join), all the rows from the "Outer" side are added back in before moving on... Where conditions are evaluated after all joins are done...
SELECT E.EntityID, E.ShortName, S.ScheduleID
FROM tblEntities E
Left Join tblScheduling S
ON S.EntityID = E.EntityID
And S.SchedulingYearID = #SchedulingYearID
WHERE E.Active = 1
ORDER BY E.EntityID
I change your join order cause I prefer left joins... but it doesn't matter
It's your conditions in the where clause:
(tblScheduling.SchedulingYearID = #SchedulingYearID)
when there is no tblScheduling info this wil always fail. Add
(((tblScheduling.SchedulingYearID = #SchedulingYearID) OR (tblScheduling.SchedulingYearID is null) )
or wathever null condition checking your DB uses.
I think the trouble is that the WHERE clause is filtering out the rows where SchedulingYearID is null. So don't.
SELECT tblEntities.EntityID, tblEntities.ShortName, tblScheduling.ScheduleID
FROM tblScheduling RIGHT OUTER JOIN
tblEntities ON tblScheduling.EntityID = tblEntities.EntityID
WHERE (tblScheduling.SchedulingYearID = #SchedulingYearID OR
tblScheduling.SchedulingYearID IS NULL)
AND (tblEntities.Active = 1)
ORDER BY tblEntities.EntityID;