How to apply a single query that sum column for individual values - sql

I have 2 tables named user and statistics
user table has 3 columns: id, name and category
statistics table has 3 columns: id, idUser (relational), cal
something like this:
user
Id name category
1 name1 1
2 name2 2
3 name3 3
statistics
Id idUser cal
1 1 1
2 1 1
3 1 1
4 2 1
5 2 1
How can I apply a query that sum the cal column by each category of users and give me something like this:
category totalcal
1 3
2 2
3 0

You want to do a left join to keep all the categories. The rest is just aggregation:
select u.category, coalesce(sum(s.cal), 0) as cal
from users u left join
statistics s
on u.id = s.idUser
group by u.category;

Use LEFT JOIN to get 0 sum for the category=3:
SELECT
user.category
,SUM(statistics.cal) AS totalcal
FROM
user
LEFT JOIN statistics ON statistics.idUser = user.Id
GROUP BY
user.category
Here SUM would return NULL for category=3. To get 0 instead of NULL you can use COALESCE(SUM(statistics.cal), 0).

Related

How to check the count of each values repeating in a row

I have two tables. Data in the first table is:
ID Username
1 Dan
2 Eli
3 Sean
4 John
Second Table Data:
user_id Status_id
1 2
1 3
4 1
3 2
2 3
1 1
3 3
3 3
3 3
. .
goes on goes on
These are my both tables.
I want to find the frequency of individual users doing 'status_id'
My expected result is:
username status_id(1) status_id(2) status_id(3)
Dan 1 1 1
Eli 0 0 1
Sean 0 1 2
John 1 0 0
My current code is:
SELECT b.username , COUNT(a.status_id)
FROM masterdb.auth_user b
left outer join masterdb.xmlform_joblist a
on a.user1_id = b.id
GROUP BY b.username, b.id, a.status_id
This gives me the separate count but in a single row without mentioning which status_id each column represents
This is called pivot and it works in two steps:
extracts the data for the specific field using a CASE statement
aggregates the data on users, to make every field value lie on the same record for each user
SELECT Username,
SUM(CASE WHEN status_id = 1 THEN 1 END) AS status_id_1,
SUM(CASE WHEN status_id = 2 THEN 1 END) AS status_id_2,
SUM(CASE WHEN status_id = 3 THEN 1 END) AS status_id_3
FROM t2
INNER JOIN t1
ON t2.user_id = t1._ID
GROUP BY Username
ORDER BY Username
Check the demo here.
Note: This solution assumes that there are 3 status_id values. If you need to generalize on the amount of status ids, you would require a dynamic query. In any case, it's better to avoid dynamic queries if you can.

Left Join Display All Data From Table1 and Table2

I am trying to do a left join so that I get all of my rows from Table 1 even if there is no value corresponding to it in the second table.
My structures are:
Location Table:
ID LocName
1 Trk1
2 Trk2
3 Trk3
4 Unk
Quantity Table:
ID PartID Quantity LocationID
1 1 2 1
2 3 12 2
3 2 6 1
4 6 8 3
5 6 5 1
I am trying to join but also make a query on a specific PartID. My query is:
SELECT
INV_LOCATIONS.ID AS LocationID,
INV_LOCATIONS.NAME AS LocationName,
INV_QUANTITY.QUANTITY AS Quantity
FROM INV_LOCATIONS
LEFT JOIN INV_QUANTITY ON INV_LOCATIONS.ID = INV_QUANTITY.LOCATION_ID
WHERE INV_QUANTITY.PART_ID = 1;
My output right now would be:
ID LocName Quantity
1 Trk1 5
3 Trk3 8
The Desired output is:
ID LocName Quantity
1 Trk1 5
2 Trk2 NULL/0
3 Trk3 8
4 Unk NULL/0
I assume it is because I have the WHERE INV_QUANTITY.PART_ID = 1 and that is forcing it to be in the quantity table. I need to be able to verify it is on the right part but how do I also include it if it doesn't exist. I know I have done something very similar before but I cannot remember which project and so I cannot find the code anywhere.
You need to move the filtering logic to the ON clause:
SELECT il.ID AS LocationID, il.NAME AS LocationName,
iq.QUANTITY AS Quantity
FROM INV_LOCATIONS il LEFT JOIN
INV_QUANTITY iq
ON il.ID = iq.LOCATION_ID AND iq.PART_ID = 1;

List rows by count when some rows refer to another row

I'm attempting to write a query that will list items from Table 2 in order of how many rows reference it in Table 1. The difficulty is that some rows in Table 2 are actually based on another row in Table 2, in which case the row it refers to should be counted instead.
My structure looks like this:
Table 1
itemID templateID
1 1
2 2
3 3
4 4
5 5
Table 2
templateName templateID basedOnTemplateID
Foo 1 null
Bar 2 null
Tree 3 1
Dog 4 2
Bird 5 null
Desired Results
templateName templateID itemCount
Foo 1 2
Bar 2 2
Bird 5 1
Tree 3 0
Dog 4 0
What I have so far:
SELECT TOP (5)
Max(table2.templateName) 'templateName',
Max(table2.templateID) 'templateID',
Count([itemID]) 'itemCount'
FROM table1
LEFT JOIN
table2 on table1.templateid = (
CASE
WHEN table2.basedOnTemplateID is not null
THEN table2.basedOnTemplateID
ELSE table2.templateID
END)
GROUP BY table2.templateid
ORDER BY Count(itemID) DESC
You can left join and aggregate as follows:
select
t2.templateName,
t2.templateID,
count(t1.templateID) itemCount
from table2 t2
left join table1 t1
on t1.templateID = t2.templateID
and t2.basedOnTemplateID is null
group by t2.templateName, t2.templateID
order by itemCount desc, t2.templateID

How to compare each group of one table with a column in another table?

I have two tables:
TypeTable
TypeId PersonClassificationId
----------------------
1 1
1 2
1 3
2 1
2 2
PersonClassificationTable
PersonClassificationId Capacity
----------------------
1 2
2 2
3 2
I need to select such TypeId that in the entire TypeTable table do not have at least one PersonClassificationID specified in PersonTable.
So, if PersonTable has 1, 2, 3, then TypeId = 2 should be selected, because there is no record in TypeTable:
TypeId PersonClassificationId
----------------------
2 3
How can I do that?
It is undesirable to use cursors : )
I think that you can do what you want by generating all possible combinations of types and classifications, and then filter on those that do not exist in the mapping table:
select t.TypeId, pc.PersonClassificationId
from (select distinct TypeId from TypeTable) t
cross join PersonClassificationTable p
where not exists (
select 1
from TypeTable t1
where t1.TypeId = t.TypeId and t1.PersonClassificationId = p.PersonClassificationId
)

SQL Search for missing record, then insert value

Below is a very oversimplified problem I am trying to solve
I have the following tables:
**quiz**
id title
--------------
1 first
2 second
3 third
4 fourth
5 fifth
**quiz_status**
id status user_id quiz_id
-------------------------------
1 0 1 1
2 0 1 2
3 0 1 3
if a I run the following:
select *
from quiz as q
left join quiz_status as qs
ON q.id = qs.quiz_id
where qs.user_id=1
I'd get:
id title id status user_id quiz_id
-------------------------------------------
1 first 1 0 1 1
2 second 2 0 1 2
3 third 3 0 1 3
4 fourth null null null null
5 fifth null null null null
I would like to be able to insert values where missing/null in the quiz_status table.
so the final outcome would be:
id title id status user_id quiz_id
-------------------------------------------
1 first 1 0 1 1
2 second 2 0 1 2
3 third 3 0 1 3
4 fourth 4 0 1 4
5 fifth 5 0 1 5
What would be the insert statement for that?
Consider the insert ... select syntax:
insert into quiz_status(status, user_id, quiz_id)
select 0, u.user_id, q.id
from (select distinct user_id from quiz_status) u
cross join quiz q
left join quiz_status qz on q.id = qz.quiz_id and u.user_id = qz.user_id
where qz.quiz_id is null
This works by generating all combinations of users and quizs, and then left joining the status table to filter on missing records. In the real life, you would likely have a users table that you can use in place of the select distinct subquery.
If you need just one user it's simpler:
insert into quiz_status(status, user_id, quiz_id)
select 0, 1, q.id
from quiz q
left join quiz_status qz on q.id = qz.quiz_id and qz.user_id = 1
where qz.quiz_id is null
Note: presumably, id is a serial column so I left it apart in the inserts.