Aggregate query across two tables in SQL? - sql

I'm working in BigQuery. I've got two tables:
TABLE: orgs
code: STRING
group: STRING
TABLE: org_employees
code: STRING
employee_count: INTEGER
The code in each table is effectively a foreign key. I want to get all unique groups, with a count of the orgs in them, and (this is the tricky bit) a count of how many of of those orgs only have a single employee. Data that looks like this:
group,orgs,single_handed_orgs
00Q,23,12
00K,15,7
I know how to do the first bit, get the unique groups and count of associated orgs from the orgs table:
SELECT
count(code), group
FROM
[orgs]
GROUP BY group
And, I know how to get the count of single-handed orgs from the practice table:
SELECT
code,
(employee_count==1) AS is_single_handed
FROM
[org_employees]
But I'm not sure how to glue them together. Can anyone help?

for BigQuery: legacy SQL
SELECT
[group],
COUNT(o.code) as orgs,
SUM(employee_count = 1) as single_handed_orgs
FROM [orgs] AS o
LEFT JOIN [org_employees] AS e
ON e.code = o.code
GROUP BY [group]
using LEFT JOIN in case if some codes are missing in org_employees tables
for BigQuery: standard SQL
SELECT
grp,
COUNT(o.code) AS orgs ,
SUM(CASE employee_count WHEN 1 THEN 1 ELSE 0 END) AS single_handed_orgs
FROM orgs AS o
LEFT JOIN org_employees AS e
ON e.code = o.code
GROUP BY grp
Note use of grp vs group - looks like standard sql does like use of Reserved Keywords even if i put backticks around
Confirmed:
you can use keyword with backticks around

You could join the two tables to get the groups that have just one employee. Then you wrap this in a sub query and you count the groups that you have.
I'm using a COUNT DISTINCT and GROUP BY because I don't know how your data is structured. Is there only a single line per group or multiple?
SELECT
COUNT(DISTINCT group)
FROM (
SELECT
group
FROM
orgs AS o INNER JOIN org_employees AS e ON o.code = e.code
WHERE
employee_count = 1
GROUP BY
group
)

Related

Issues with Counting Records with SQL across multiple tables

There are three tables: Cases, Calls, and SubEvents.
The table schema is a Case can have multiple Calls, and each Call can have multiple SubEvents.
I'd like to use a query to get a count of all calls and a count of all sub-events (if there are any) for each case after a certain date.
For example, a case named John has 3 calls... the first call has 2 sub-events, the second call has 1 sub-event, and the third call has zero. So the query should return this result:
Case
Call Total
SubEvent Total
John
3
3
I've tried writing the query multiple ways, with subqueries etc, but I can't get it to work properly. The closest I've come is the query below, but this provides the incorrect count for Calls. It gives me 4 when it should give me 3. Another example I tried had 4 calls with 10 sub-events, but the query returned 11 total calls instead of 4.
I'd appreciate any help. My SQL has gotten rusty after a period of disuse, and this is in someone's Access database, which is pretty fickle when it comes to writing SQL queries.
SELECT c.casename, Count(e.callid) AS EventTotal, Count(s.id) AS SubEventTotal
FROM (cases AS c INNER JOIN calls AS e ON c.contactid = e.contactid) left JOIN tblSubEvents AS s ON e.callid = s.callid
WHERE e.calldate > #1/1/2022#
GROUP BY c.casename
Try this:
SELECT
c.casename
,Count(e.callid) AS EventTotal
,sum(s.id) AS SubEventTotal
FROM (cases AS c INNER JOIN calls AS e ON c.contactid = e.contactid)
left JOIN (select callid, count(s.id) as id from tblSubEvents s group by callid) AS s ON e.callid = s.callid
WHERE e.calldate > #1/1/2022#
GROUP BY c.casename
Basically, pushing the responsibility for the sub-event count to the join query.
Consider joining two aggregate derived tables:
SELECT case.casename, c_agg.EventTotal, e_agg.SubEventTotal
FROM (case
INNER JOIN (
SELECT contactid, COUNT(callid) AS EventTotal
FROM calls
WHERE calldate > CDate('2022-01-01')
GROUP BY contactid
) c_agg
ON case.contactid = c_agg.contactid)
LEFT JOIN (
SELECT callid, COUNT(id) AS SubEventTotal
FROM tblSubEvents
GROUP BY callid
) e_agg
ON c_agg.callid = e_agg.callid

Oracle - select statement to rollup multiple tables within a time frame

I have 3 Oracle tables for a project that link a demo Transaction table to Transaction_Customer and Transaction_Employee as shown below. Each transaction can have multiple customers involved and many employees involved.
I am trying to write a SQL query which will list each Customer_ID that has had transactions with multiple employees within a one period. I would like the output to include a single row for each Customer_ID with a comma separated list of which Employee_IDs had a transaction with that customer.
The output should look like this:
Customer_ID|Employees
601|007,008,009
The basic query to join the tables together looks like this:
select * from transactions t
left join transactions_customer tc
on t.t_id = tc.t_id
left join transactions_employee te
on t.t_id = te.t_id
How do I get this do I finish this assignment and get the query working the way intended?
Thank you!
Transactions
T_ID|Date|Amount
1|1/10/2017|100
2|1/10/2017|200
3|1/31/2017|150
4|2/16/2017|175
5|2/17/2017|175
6|2/18/2017|185
Transactions_Customer
T_ID|Customer_ID
1|600
1|601
1|602
2|605
3|606
4|601
5|607
6|607
Transactions_Employee
T_ID|Employee_ID
1|007
1|008
2|009
3|008
4|009
5|007
6|007
Is this what you want?
select tc.Customer_id,
listagg(te.employee_id, ',') within group (order by te.employee_id) as employees
from Transactions_Customer tc join
Transactions_Employee te
on tc.t_id = te.t_id
group by tc.Customer_id;
You only need the Transactions table for filtering on the date. Your question alludes to such filtering but does not exactly describe it, so I left it out.
Edit:
The customer data (and perhaps the employees data too) has duplicates. To avoid these in the output:
select tc.Customer_id,
listagg(te.employee_id, ',') within group (order by te.employee_id) as employees
from (select distinct tc.t_id, tc.customer_id
from Transactions_Customer tc
) tc join
(select distinct te.t_id, te.employee_id
from Transactions_Employee te
) te
on tc.t_id = te.t_id
group by tc.Customer_id;

How do I count from 2 different tables in access sql

I have two tables, one that contains information about patients visits: PatientName,DoctorName,DataOfVisit, etc and the second table that contains information about doctors: DoctorName and DoctorSpeciality.
I need to create a query that will print me the PatientName, the number of doctors that patient went to, and the number of different specialties.
If I run
SELECT PatientName, COUNT(VISITS.DoctorName) as DocNum, Count(DoctorSpeciality) as SpecNum
FROM VISITS
INNER JOIN Doctors
ON VISITS.DoctorName = Doctors.DoctorName
GROUP BY PatientName, VISITS.DoctorName, DoctorSpeciality
I get the number of Doctors but not the number of Specialities and the patients are not grouped.
In most databases, you would just use count(distinct specialty). But, Access doesn't support that.
You can do what you want with two group bys:
SELECT PatientName, COUNT(*) as NumSpecialties, SUM(NumDocs) as NumDocs
FROM (SELECT PatientName, Doctors.DoctorSpeciality, COUNT(*) as NumDocs
FROM VISITS INNER JOIN
Doctors
ON VISITS.DoctorName = Doctors.DoctorName
GROUP BY PatientName, DoctorSpeciality
) as pd
GROUP BY PatientName;
You can add DISTINCT within your COUNT() function, also you should not include the aggregate fields in your GROUP BY.
Here is how I would change the query.
SELECT PatientName, COUNT(DISTINCT VISITS.DoctorName) as DocNum,
Count(DISTINCT DoctorSpeciality) as SpecNum
FROM VISITS INNER JOIN
Doctors ON VISITS.DoctorName = Doctors.DoctorName
GROUP BY PatientName
use table name with fields that you want to select from db
SELECT VISITS.PatientName, COUNT(VISITS.DoctorName) as DocNum, Count(Doctors.DoctorSpeciality) as SpecNum
FROM VISITS
INNER JOIN Doctors
ON VISITS.DoctorName = Doctors.DoctorName
GROUP BY PatientName, VISITS.DoctorName, DoctorSpeciality

Sub query to count number of time an id appears in another table

Using SQL Server 2012. I have a table called deals that contains a primary key called deal_id along with 10 other fields. I also have a table called deals_country that contain a foreign key called deal_id.
It's possible that a record in deals contains numerous records in deals country. What I want to do is to count the number of times every deal_id from deals appears in deals_country?
Below is what I have tried without success.
select MA_DEALS.*, MA_DEALS_COUNTRY.mycount
from MA_DEALS cross apply
(
select count(MA_DEALS_COUNTRY.deal_id) as mycount
from MA_DEALS_COUNTRY
group by MA_DEALS_COUNTRY.deal_id
) MA_DEALS_COUNTRY
order by MA_DEALS.deal_id
Although you can use CROSS APPLY for this, I would start with the basic JOIN and GROUP BY query instead:
select MA_DEALS.*, dc.mycount
from MA_DEALS d left join
(select dc.deal_id, count(dc.deal_id) as mycount
from MA_DEALS_COUNTRY dc
group by dc.deal_id
) dc
on d.deal_id = dc.deal_id
order by d.deal_id;
Try this:
SELECT D.*,
DC.N
FROM MA_DEALS D
LEFT JOIN ( SELECT deal_id, COUNT(*) N
FROM MA_DEALS_COUNTRY
GROUP BY deal_id) DC
ON D.deal_id = DC.deal_id

Combining data from 2 tables in to 1 query

Hi all
Im having some problems combining data from 2 tables in to 1 query.
Now I have one table-nr1 with raw data of restaurants and in the other table-nr2 I have a number of restaurants that have been graded.
So, now I want to select all restaurants and at the same time select grades of that restaurant from table-nr2 and get the average value of those grades.
How can I do this in a single SQL query?
SELECT r.*,
COALESCE(
(
SELECT AVG(grade)
FROM table_nr2 g
WHERE g.restaurant_id = r.id
), 0)
FROM table-nr1 r
Assuming your restaurants have a name and id, and the your reviews have a grade
SELECT re.name, avg(ra.grade)
FROM table-nr1 re
LEFT JOIN table-nr2 ra ON re.id = ra.id
GROUP BY re.name
You need to group by all fields you want to select which are not aggregated, and left join means you will get all restaurants, irrespective of whether they have any ratings.
You need to perform a join. In this case an inner left join sounds fine, which is the default join. You can use USING syntax if the field that links them is the same on both sides, so you would end up with something like this:
SELECT table-nr1.*, AVG(table-nr2.score)
FROM table-nr1
JOIN table-nr2 USING (restrauntId)
Otherwise you could do something that links them using an on clause like this:
SELECT table-nr1.*, AVG(table-nr2.score)
FROM table-nr1
JOIN table-nr2 ON (table-nr1.restrauntId = table-nr2.restrauntId)