Deriving Data from Multiple Tables & Joining in Oracle - sql

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

Related

Access SQL: How to retrieve sums of multiple values where user IDs are assigned to multiple positions

I'm working on an Access database for assigning tasks to personnel and tracking task status and workload. A single user ID can be assigned to one of many fields associated with a particular task. In this case, the Task table has fields for "TechReviewerID" "DesignerID" "TechReviewerWorkload" and "DesignerWorkload."
I want one query to return one row for each person, with two summary columns totaling all of the workload assigned to them. So if I'm ID1, I want column 3 to return the sum of "TechReviewerWorkload" in all tasks where "TechReviewerID = 1" and column 4 to return the sum of "DesignerWorkload" in all tasks where "DesignerID = 1."
I have successfully written two separate queries that accomplish this:
SELECT MESPersonnel.MESID, MESPersonnel.PersonnelName,
IIF(SUM(DesignerTask.DesignerWorkload) IS NULL, 0, SUM(DesignerTask.DesignerWorkload)) AS
TotalDesignerWorkload
FROM
(MESPersonnel LEFT OUTER JOIN Task AS DesignerTask ON (MESPersonnel.MESID =
DesignerTask.DesignerID
AND DesignerTask.DueDate < CDATE('2020-07-30') AND DesignerTask.DueDate > CDATE ('2020-05-01')))
WHERE MESPersonnel.PositionID = 1
GROUP BY MESPersonnel.MESID, MESPersonnel.PersonnelName;
This query gives the following table:
MESID PersonnelName TotalDesignerWorkload
1 John Doe 40
2 Dohn Joe 20
I can create a near-identical query by replacing all instances of "designer" terms with "tech reviewer" terms.
What I'm looking for is a table like:
MESID PersonnelName TotalDesignerWorkload TotalReviewerWorkload
1 John Doe 40 10
2 Dohn Joe 20 20
My attempts to combine these two via multiple outer joins resulted in wildly inaccurate sums. I know how to solve that for items on different tables, but I'm not sure how to resolve it when I'm using two items from the same table. Is there some kind of conditional sum I can use in my query that Access supports?
EDIT: Sample Raw Data
Task Table
TaskID DesignerID TechReviewerID DesignerWorkload TechReviewerWorkload DueDate
1 1 2 40 20 06-20-2020
2 2 1 20 10 06-20-2020
MESPersonnel Table
MESID PersonnelName
1 John Doe
2 Dohn Joe
Consider:
Query1: TaskUNION
rearranges data to a normalized structure
SELECT TaskID, DesignerID AS UID, PersonnelName, DesignerWorkload AS Data, DueDate, "Design" AS Cat FROM MESPersonnel
INNER JOIN Task ON MESPersonnel.MESID = Task.DesignerID
UNION SELECT TaskID, TechReviewerID, PersonnelName, TechReviewerWorkload, DueDate, "Tech" FROM MESPersonnel
INNER JOIN Task ON MESPersonnel.MESID = Task.TechReviewerID;
Query2:
TRANSFORM Sum(Data) AS SumData
SELECT UID, PersonnelName
FROM TaskUNION
WHERE DueDate BETWEEN #5/1/2020# AND #7/31/2020#
GROUP BY UID, PersonnelName
PIVOT Cat;
An alternative would involve 2 simple, filtered aggregate queries on Task table then join those 2 queries to MESPersonnel. Here as all-in-one statement:
SELECT MESID, PersonnelName, SumOfDesignerWorkload, SumOfTechReviewerWorkload
FROM (
SELECT DesignerID, Sum(DesignerWorkload) AS SumOfDesignerWorkload
FROM Task WHERE DueDate BETWEEN #5/1/2020# AND #7/31/2020# GROUP BY DesignerID) AS SumDesi
RIGHT JOIN ((
SELECT TechReviewerID, Sum(TechReviewerWorkload) AS SumOfTechReviewerWorkload
FROM Task WHERE DueDate BETWEEN #5/1/2020# AND #7/31/2020# GROUP BY TechReviewerID) AS SumTech
RIGHT JOIN MESPersonnel ON SumTech.TechReviewerID = MESPersonnel.MESID)
ON SumDesi.DesignerID = MESPersonnel.MESID;

How to order by, sum, and join using ActiveRecord

I have two tables:
USERS
id name
------------
1. bill
2. dave
3. kate
4. sara
and
GAMES
score user_id
------------------
10 1
0 1
0 2
10 3
0 2
10 3
0 3
0 4
This query:
SELECT users.name, SUM(games.score) AS total FROM users JOIN games
ON users.id = games.user_id ORDER BY total LIMIT 2;
produces output like this:
name total
-------------
kate 20
bill 10
What is the correct Rails convention here for ActiveRecord to perform an ORDER BY with SUM and JOIN?
You're wanting to select the sum of scores of total games from each user...
You don't always have to copy the sql syntax over..just think about how to do it in rails with their query methods..
# Creates an array of all of the records that exist under the user_id of the
# current user being looped and adds all of those records together, you can
# handle whatever you want to do with that data here. Say put it in an associate # table, or run some logic on it. This is the total amount
Users.all.each do |user|
total = Games.where(user_id: user.id).inject(0, :+)
logger.info "User: #{user.id}"
logger.info "Total: #{total}"
end

SQL oracle: Display records that are not found in another table

I have tried to fetch a record that will return me with the doctor's ID and the total number of all the prescriptions they have given.
SELECT doc.DID, COUNT(pr.DID)
FROM DOCTOR doc, PRESCRIPTION pr
WHERE doc.DID = pr.DID
GROUP BY doc.DID;
By using this statement, I am able to receive the information as long as there is at least one prescription made by a doctor. This is how my results looks like
DID COUNT(PR.DID)
-------------------- -------------
3292848 1
3292885 10
3293063 10
3332949 15
3332950 2
But I want it to display such that even doctors that has not prescribed before will be shown in the record with a count of 0
DID COUNT(PR.DID)
-------------------- -------------
3292848 1
3292885 10
3293042 0
3293063 10
3332949 15
3332950 2
334021 0
First of all, please avoid using old join syntax. Use proper JOIN syntax.
Now here you need a LEFT JOIN which would give you everything from first table and matching records from second table. For non matching records, you will get null, which you can utilize in where or select clause.
SELECT doc.DID, COUNT(pr.DID)
FROM DOCTOR doc
left join
PRESCRIPTION pr
on doc.DID = pr.DID
GROUP BY doc.DID;

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

Progressive count using a query?

I use this query to
SELECT userId, submDate, COUNT(submId) AS nSubms
FROM submissions
GROUP BY userId, submDate
ORDER BY userId, submDate
obtain the total number of submissions per user per date.
However I need to have the progressive count for every user so I can see how their submissions accumulate over time.
Is this possible to implement in a query ?
EDIT: The obtained table looks like this :
userId submDate nSubms
1 2-Feb 1
1 4-Feb 7
2 1-Jan 4
2 2-Jan 2
2 18-Jan 1
I want to produce this :
userId submDate nSubms progressive
1 2-Feb 1 1
1 4-Feb 7 8
2 1-Jan 4 4
2 2-Jan 2 6
2 18-Jan 1 7
EDIT 2 : Sorry for not mentioning it earlier, I am not allowed to use :
Stored procedure calls
Update/Delete/Insert/Create queries
Unions
DISTINCT keyword
as I am using a tool that doesn't allow those.
You can use a self-join to grab all the rows of the same table with a date before the current row:
SELECT s0.userId, s0.submDate, COUNT(s0.submId) AS nSubms, COUNT (s1.submId) AS progressive
FROM submissions AS s0
JOIN submissions AS s1 ON s1.userId=s0.userId AND s1.submDate<=s0.submDate
GROUP BY s0.userId, s0.submDate
ORDER BY s0.userId, s0.submDate
This is going to force the database to do a load of pointless work counting all the same rows again and again though. It would be better to just add up the nSubms as you go down in whatever script is calling the query, or in an SQL variable, if that's available in your environment.
The Best solution for this is to do it at the client.
It's the right tool for the job. Databases are not suited for this kind of task
Select S.userId, S.submDate, Count(*) As nSubms
, (Select Count(*)
From submissions As S1
Where S1.userid = S.userId
And S1.submDate <= S.submDate) As TotalSubms
From submissions As S
Group By S.userid, S.submDate
Order By S.userid, S.submDate