Query with two joins and two tables - sql

For the simplification of the problem, lets say I have 2 tables:
user
id: int
ticket
id: int
user_id: int
marked: bool
With the given example data:
user
id
1
2
3
4
5
ticket
id
user_id
marked
1
1
false
2
1
true
3
1
true
4
2
true
5
2
false
6
2
false
7
3
false
8
5
false
9
5
false
User 1 and 2 have marked tickets.
User 3 has 1 unmarked ticket.
User 4 has no tickets.
User 5 has 2 unmarked tickets.
And I need a query that returns tickets with id 7, 8 and 9 - the tickets of users who don't have marked tickets.
I've written the following query:
SELECT * FROM ticket t
INNER JOIN user u ON t.user_id=u.id
INNER JOIN ticket tt ON u.id = tt.user_id
WHERE tt.marked = false;
But it doesn't works as expected. I don't want to use subqueries to exclude users with marked tickets. Can this be done fully with JOINs? So it happens that I'm not that familiar with JOIN clauses.

This assumes marked is an int. You may need to adjust your query to convert your bool data type.
with a as (
select t.user_id
, max(t.marked) as marked
from ticket t
group by t.user_id
)
select t.*
from ticket t
inner join a on a.user_id = t.user_id
where a.marked = 0
I deliberately omitted user since it adds no value.

I'm hesitant to answer without more info, but subqueries may be helpful.
set up and post a repel for us to try it out.
If you're not familiar, here's a brief video on subqueries.
https://www.youtube.com/watch?v=GpC0XyiJPEo&t=417s

Related

Access "Not In" query not working while only In is working correctly

I have below given query which is working fine but I want to use "Not In" operator instead of "In" but its giving no results:
SELECT DISTINCT OrderProdDetails.Priority
FROM OrderProdDetails
WHERE (((OrderProdDetails.Priority) In (SELECT DISTINCT OrderProdDetails.Priority
FROM OrderProdDetails WHERE (((OrderProdDetails.OrdID)=[Forms]![UpdateOrder]![OdrID])))));
Desired Query:
SELECT DISTINCT OrderProdDetails.Priority
FROM OrderProdDetails
WHERE (((OrderProdDetails.Priority) Not In (SELECT DISTINCT OrderProdDetails.Priority
FROM OrderProdDetails WHERE (((OrderProdDetails.OrdID)=[Forms]![UpdateOrder]![OdrID])))));
Basically it is referencing a control on parent form and based on that in a subform I want to populate the priority numbers i.e 1,2,3 and if for that record 1 is entered I want to get only 2 and 3 as drop-down option.
ReocordID OrdID Brand Name Priority
2 1 Org 1 2
3 2 Org 2 1
4 1 Org 1 1
6 1 Org 1 3
7 3 Org 3 1
8 4 Org 1 1
9 5 Org 2 1
10 5 Org 2 2
11 6 Org 1 1
12 6 Org 2 2
If there is any other better approach for the same please suggest.
Thanks in advance for your help.
In all likelihood, your problem is that Priority can take on NULL values. In that case, NOT IN doesn't work as expected (although it does work technically). The usual advice is to always use NOT EXISTS with subqueries rather than NOT IN.
But, in your case, I would suggest conditional aggregation instead:
SELECT opd.Priority
FROM OrderProdDetails as opd
GROUP BY opd.Priority
HAVING SUM(IIF(opd.OrdID = [Forms]![UpdateOrder]![OdrID], 1, 0)) = 0;
The HAVING clause counts the number of times the forms OdrId is in the orders. The = 0 means it is never there. Plus, you no longer need a select distinct.
Thanks for your prompt answers however I figured out what the problem was and the answer to problem is.
SELECT DISTINCT OrderProdDetails.Priority
FROM OrderProdDetails
WHERE (((OrderProdDetails.Priority) Not In (SELECT OrderProdDetails.Priority
FROM OrderProdDetails WHERE (((OrderProdDetails.OrdID)=[Forms]![UpdateOrder]![OdrID])
and ((OrderProdDetails.Priority) Is not null) ))));
I realized that the problem was happening only to those where there was a null value in priority so I puth the check of not null and it worked fine.
Thanks

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

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;