Access SQL Syntax for Cross-Table Count - sql

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

Related

SQL subquery to join the most recent plan for a client

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

Deriving Data from Multiple Tables & Joining in Oracle

Users will be recording data using the following two tables:
USERS:
UserID UserName UserType
1 Tom 5
2 Mike 6
3 Joe 6
RECORDINGS :
UserID Recording
1 10
1 15
I want to use a single query to find the Name, and the count of recordings made by each user whose UserType is above the average of UserType. In the event a user has never made a recording, it needs to be 0 (not null or missing).
My approach is to first select the users who are above average, second to select the count of recordings made by each user, and third to join the two where UserID matches. Is there a more straight forward approach?
SELECT usr.UserID
,COUNT(rec.Recording) Count
FROM USers usr
,Recordings rec
,(SELECT AVG(UserType) average
FROM USers usr1) avg1
WHERE usr.Userid = rec.userid(+)
AND avg1.average < usr.UserType
GROUP BY usr.UserID
Please check if this works.
http://sqlfiddle.com/#!4/a03d2/5/0

Multiple Joins to get data and counts from multiple tables

This is probably really simple, but I have been struggling. Basically I need to combine 2 different queries:
Get a list of accounts plus some info for each
Based on each of those accounts, get the count of users and forms associated with each.
So given the following table structure:
I want to get back:
Name Users Forms Active
====================================
Child 1 3 4 T
Child 2 4 3 F
So the problem is that I want to query first based on the Master id:
Select * from ACCOUNT where MasterId = 1026
AccntId Name Master Id Active
====================================
2 Child 1 1026 T
3 Child 2 1026 F
Then for each of those returned I would like to get the counts of users and forms.
Select Count(AccntId) as Users from Form Where AccntId=2
And of course all in one query. I have messed around with Joins and Left Joins and the stumbling block in the initial query.
Ok, the final query for anyone who cares turned out to be:
SELECT
A.Id as AccountId, A.Name, A.Active,
(select count(*) as Users FROM UserProfile UP where A.Id = UP.AccountId),
(select count(*) as Forms FROM Form F where A.Id = F.AccountId)
FROM
Account A
WHERE
A.MasterId = 1026
Group By A.Id, A.Name, A.Active
Which gave me ultimately the numbers I was looking for:
AccountId Name Active Users Forms
1 Child T 3 4
5 Child2 F 4 3
Not sure if that is the most efficient or proper approach, but it does work! Thanks for the hints from the commentators
SELECT acc.MasterId, count(up.AccntId) as Users, count(f.AccntId) as Forms
from Account acc
full join UserProfile up
on up.AccntId = acc.AccntId
full join Form f
on f.AccntId = acc.AccntId
-- Where /* Your conditions */
group by acc.MasterId;
This should work.
Edit: joins changed to left join

Retrieve a record that has 2 specific features in SQL

I have the following database of pictures (a picture can have multiple features):
Table Picture
-------------
ID Name
1 Mona Lisa
2 Scream
Table Features
-------------
ID Name PictureID (FK to Picture)
1 Portrait 2
2 Expressive 2
3 Big 2
4 Small 1
5 Expressive 1
5 Big 1
I'd wish to do a query that retrieves all the Pictures that are a Portrait AND Big, (so the result would be in this case "Scream"). I've come up with this query to retrieve it, but I'm not sure if it is the prettiest and most efficient way to do it. Here's my proposal:
SELECT *
FROM Picture o
WHERE
(select count(*)
from Feature c
where o.id = c.pictureID and c.Name like '%Portrait%') >= 1
AND
(select count(*)
from Feature c
where o.id = c.pictureID and c.Name like '%Big%') >= 1
In this case, I have to go through the Features table twice (which, to my personal taste, I find it "ugly").
Thanks and regards
SELECT picture.name FROM picture
JOIN features
on picture.id=features.pictureID
WHERE features.name IN('Portrait','Big')
GROUP BY features.pictureID
HAVING COUNT(DISTINCT features.ID)>=2

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)