Join with other table and get aggregated d - sql

I have two table User and Score, each user have multiple score. How can I query average score with user name:
Ex:
Jack 6
Sham 5
User
Name user_id
Jack 123
Tony 234
Sham 456
Score
id score user_id
1 4 123
2 8 123
3 9 234
4 2 456
5 10 456
6 3 456

If I understand, this is a join and group by:
select u.name, avg(s.score)
from users u join
scores s
using (user_id)
group by user_id, u.name;
Note that I've included user_id in the group by, in case two users have the same name.

Related

Select max date for each register, null if does not exists

I have these tables: Employee (id, name, number), Configuration (id, years, licence_days), Periods (id, start_date, end_date, configuration_id, employee_id, period_type):
Employee table:
id name number
---- ----- -------
1 Bob 355
2 John 467
3 Maria 568
4 Josh 871
configuration table:
id years licence_days
---- ----- ------------
1 1 8
2 3 16
3 5 24
Periods table:
id start_date end_date configuration_id employee_id period_type
---- ---------- ------- ---------------- ----------- -----------
1 2021-05-23 2021-05-31 1 1 vaccation
2 2021-05-24 2021-06-01 1 2 vaccation
3 2021-03-01 2021-03-17 2 2 vaccation
4 2021-05-05 2021-05-21 2 2 vaccation
5 2021-01-01 2021-01-17 2 4 vaccation
I want this result:
Result:
employee_id years licence_days max(end_date)
1 1 8 2021-05-31
1 3 16 null
1 5 24 null
2 1 8 2021-06-01
2 3 16 2021-05-21
2 5 24 null
3 1 8 null
3 3 16 null
3 5 24 null
4 1 8 null
4 3 16 2021-01-17
4 5 24 null
i.e., I want to select all Employees with all configuration, and for each one of that, the max end_date of the "vaccation" type (or null if it does not exists).
How can I do that
Oracle supports cross joins, right? So may be something like that?
SELECT e.employee_id, c.years, c.licence_days, max(p.end_date)
FROM Employee e
CROSS JOIN configuration c
LEFT JOIN Periods p
ON e.employee_id = p.employee_id
AND c.configuration_id = p.configuration_id
GROUP BY e.employee_id, c.years, c.licence_days
ORDER BY e.employee_id, c.years
#umberto-petrov chooses wisely with the ANSI CROSS JOIN syntax for a cartesian join. However, in the very weak probability that your requires output of configurations even where there is no employees, you can go with something like :
EDIT: Filtering the Periods join with 'vaccation' as asked in the comments.
If you have to filter for some employee ids, change ON 1 = 1 by ON Employee.id IN (id1, id2, ...). It still keeps every configurations but only takes employees that match the ids.
SELECT Employee.employee_id,
Configuration.years,
Configuration.licence_days,
MAX(Configuration.end_date) max_end_date
FROM Configuration LEFT JOIN Employee ON 1 = 1
LEFT JOIN Periods ON Periods.configuration_id = Configuration.id
AND Periods.employee_id = Employee.id
AND Periods.period_type = 'vaccation'
GROUP BY Employee.employee_id,
Configuration.years,
Configuration.licence_days
ORDER BY Employee.employee_id,
Configuration.years,
Configuration.licence_days
We start from configuration to take every records from this one at least, then made a LEFT CARTESIAN JOIN with Employee and finally a full LET JOIN on Periods for both. That way , if there is no employees, this will output configuration_id and NULL for years, licence_days and max end_date.

SQL Query: Join (or select) 2 columns from 1 table with 1 column from another table for a view without extra join columns

This is my very first Stackoverflow post, so I apologize if I am not formatting my question correctly. I'm pounding my head against the wall with what I'm sure is a simple problem. I have a table with a bunch of event information, about 10 columns as so:
Table: event_info
date location_id lead_user_id colead_user_id attendees start end <and a few more...>
------------------------------------------------------------------------------------------------
2020-10-10 1 3 1 26 2100 2200 .
2020-10-11 3 2 4 18 0600 0700
2020-10-12 2 5 6 6 0800 0900
And another table with user information:
Table: users
user_id user_name display_name email phone city
----------------------------------------------------------------------
1 Joe S goofball ...
2 John T schmoofball ...
3 Jack U aloofball ...
4 Jim V poofball ...
5 Joy W tootball ...
6 George A boring ...
I want to create a view that has only a subset of the information, not full table joins. The event table lead_user_id and colead_user_id columns both refer to the user_id column in the users table.
I want to create a view like this:
date Location Lead Name CoLead Name attendees
---------------------------------------------------------------------
2020-10-10 1 Jack U Joe S 26
2020-10-11 3 John T Jim V 18
2020-10-12 2 Joy W George A 6
I have tried the following and several iterations like it to no avail...
SELECT
E.date, E.location,
U1.display_name AS Lead Name,
U2.display_name AS CoLead Name.
E.attendees
FROM
users U1, event_info E
INNER JOIN
event_info E ON U1.user_id = E.lead_user_id
INNER JOIN
users U2 ON U2.user_id = E.colead_user_id
And I get the dreaded
You have an error in your SQL Syntax
message. I'm not surprised, as I've really only ever used joins on single columns or nested select statements... this two columns pointing to one is throwing me for a loop. Help!
correct query for this matter
SELECT
E.date, E.location,
U1.display_name AS Lead Name,
(select display_name from users where user_id=E.colead_user_id) AS CoLead Name,
E.attendees
FROM
event_info E
INNER JOIN
users U1 ON U1.user_id = E.lead_user_id

Equivalent of excel COUNTIFS

I am trying to get a COUNTIFS from excel type of result
Here is the products table:
Name Product
john car
john football
john image
max food
max tv
max laptop
max image
max image
max image
alex tv
alex laptop
alex image
alex cake
alex cake
alex cake
alex cake
alex car
The output should be:
Name Product Number of products per person Number of products of the same type
john car 1 2
john football1 1
john image 1 5
max food 1 1
max tv 1 2
max laptop 1 2
max image 3 5
alex tv 1 2
alex laptop 1 2
alex image 1 5
alex cake 4 4
alex car 1 2
Number of products per person is count of products by name by product
and Number of products of the same type is based on the total count by product
for example image is repeated 3 times for max so in col C the answer is 3 but it there 5 times in the table so answer in col D is 5
I tried but not getting the correct answer:
SELECT
name,
product,
COUNT(*),
COUNT(*) OVER (PARTITION BY product),
from products
GROUP BY 1,2
ORDER BY 1
You are quite close. You need to sum the COUNT(*). You can do this directly in the aggregation query:
SELECT name, product,
COUNT(*),
SUM(COUNT(*)) OVER (PARTITION BY product)
FROM products
GROUP BY 1, 2
ORDER BY 1
#standardSQL
SELECT name, product, product_per_person,
SUM(product_per_person) OVER(PARTITION BY product) product_total
FROM (
SELECT
name,
product,
COUNT(*) product_per_person
FROM `project.dataset.products`
GROUP BY 1,2
)
ORDER BY 1
if to apply to your sample data - result should be
Row name product product_per_person product_total
1 alex cake 4 4
2 alex car 1 2
3 alex image 1 5
4 alex laptop 1 2
5 alex tv 1 2
6 john car 1 2
7 john football 1 1
8 john image 1 5
9 max food 1 1
10 max image 3 5
11 max laptop 1 2
12 max tv 1 2
use group by name and product
SELECT name,
product,
COUNT(*),
COUNT(*) OVER (partition by product)
from products
GROUP BY name,product
ORDER BY 1

SQL query to get only rows match the condition based on two separated columns under one 'group by'

The simple SELECT query would return the data as below:
Select ID, User, Country, TimeLogged from Data
ID User Country TimeLogged
1 Samantha SCO 10
1 John UK 5
1 Andrew NZL 15
2 John UK 20
3 Mark UK 10
3 Mark UK 20
3 Steven UK 10
3 Andrew NZL 15
3 Sharon IRL 5
4 Andrew NZL 25
4 Michael AUS 5
5 Jessica USA 30
I would like to return a sum of time logged for each user grouped by ID
But for only ID numbers where both of these values Country = UK and User = Andrew are included within their rows.
So the output in the above example would be
ID User Country TimeLogged
1 John UK 5
1 Andrew NZL 15
3 Mark UK 30
3 Steven UK 10
3 Andrew NZL 15
First you need to identify which IDs you're going to be returning
SELECT ID FROM MyTable WHERE Country='UK'
INTERSECT
SELECT ID FROM MyTable WHERE [User]='Andrew';
and based on that, you can then filter to aggregate the expected rows.
SELECT ID,
[User],
Country,
SUM(Timelogged) as Timelogged
FROM mytable
WHERE (Country='UK' OR [User]='Andrew')
AND ID IN( SELECT ID FROM MyTable WHERE Country='UK'
INTERSECT
SELECT ID FROM MyTable WHERE [User]='Andrew')
GROUP BY ID, [User], country;
So, you have described what you need to write almost perfectly but not quite. Your result table indicates that you want Country = UK OR User = Andrew, rather than AND
You need to select and group by, then include a WHERE:-
Select ID, User, Country, SUM(Timelogged) as Timelogged from mytable
WHERE Country='UK' OR User='Andrew'
Group by ID, user, country

Aggregate Functions To Pull More Record Field Data

I would like to know what would be the best way to get the data from a specific row when I use a Group By query. The real query is more complex than the example I'm providing here so I'm looking for something other than a sub-select on the Sales table.
I'm using MSSQL 2008 and I would like something that allow me to get the date field from the Sales record that has the max(amount).
Query
select uid, firstName, lastName, AmountFromTagetedRow, DateFromTargetedRow,
from users u inner join
sales s on u.uid = s.custID
group by uid, firstName, lastName
order by uid
USERS
uid firstName lastName
1 Sam Smith
2 Joe Brown
3 Kim Young
SALES
sid Custid date amount ...
1 1 2016-01-02 100
2 3 2016-01-12 485
3 1 2016-01-22 152
4 2 2016-02-01 156
5 1 2016-02-02 12
6 1 2016-03-05 84
7 2 2016-03-10 68
RESULTS
uid firstName LastName amount date
1 Sam Smith 152 2016-01-22
2 Joe Brown 156 2016-02-01
3 Kim Young 485 2016-01-12
Your posted query doesn't match your amount but something like this should get you pointed in the right direction.
with SortedResults as
(
select uid
, firstName
, lastName
, AmountFromTagetedRow
, DateFromTargetedRow
, ROW_NUMBER() over (partition by u.uid order by AmountFromTagetedRow desc) as RowNum
from users u inner join
sales s on u.uid = s.custID
group by uid
, firstName
, lastName
)
select *
from SortedResults
where RowNum = 1
order by uid