I'm trying to Sum column only if id is different.
I tried like this, but it is not working:
SUM(CASE WHEN
DISTINCT empLeaves.ApprovedLeaveID
THEN empLeaves.TotalLeavesTaken END) AS Total
What Would be the proper way to SUM it?
Here is the total query, I am working on:
SELECT
E.employee_id AS EmployeeID,
E.employee_code AS EmployeeCode,
E.full_name AS EmployeeName,
empLeaves.LeavesFromDate,
empLeaves.LeavesToDate,
-- COUNT(empLeaves.ApprovedLeaveID) AS TotalApprovedApplications,
ATT.`in_date` AS InDate,
ATT.`out_date` AS OutDate,
SUM(CASE WHEN DISTINCT empLeaves.ApprovedLeaveID THEN empLeaves.TotalLeavesTaken END) AS Total
FROM employee E
LEFT JOIN `attendence` ATT ON ATT.`employee_id` = E.`employee_id`
LEFT JOIN (
SELECT
LA.`leave_approval_id` AS ApprovedLeaveID,
E.`employee_id` AS EmployeeID,
LA.`approved_from` AS LeavesFromDate,
LA.`approved_to` AS LeavesToDate,
DATEDIFF(LA.approved_to,approved_from) AS TotalLeavesTaken
FROM leave_application APP
INNER JOIN leave_approval LA
ON LA.`leave_application_id` = APP.`application_id` AND LA.`trashed` = 0 AND LA.`status` = 2
INNER JOIN employee E
ON E.`employee_id` = APP.`employee_id` AND E.`trashed` = 0 AND E.`enrolled` = 1
INNER JOIN ml_leave_type MLLT
ON MLLT.`ml_leave_type_id` = APP.`ml_leave_type_id` AND MLLT.`trashed` = 0
) empLeaves ON E.`employee_id` = empLeaves.EmployeeID
WHERE
E.`enrolled` = 1 AND E.`trashed` = 0
GROUP BY
E.`employee_id`,empLeaves.EmployeeID
When which ID is different from what?
In general, when you have a value in a field and you want to add them together except for those in a particular set of rows, you simply set the unwanted values to 0:
sum( case otherfield when somevalue then row.field else 0 end ) as SumOfValues
So when otherfield shows that this is the row you want included in the total, you expose the field you want to add (row.field in this example). Otherwise, you expose a zero. Of course, if the value you're testing is to find the rows you don't want in the total, just put the zero after the then and the field after the else.
Related
I'm just 3 months of experience in MySQL. Here I'm trying to generate a report based on log and part table. When trying to join the "Part" table twice, the "Log" table Quantity gets doubled. Kindly let me know where I'm doing wrong.
Log Table
Part Table
Expected Report
Query Used
SELECT
report.*,
(SUM(report.quantity)) AS totalQuantity,
normalPart.price AS normalPrice,
premiumPart.price AS premiumPrice
FROM
log AS report
LEFT JOIN
(SELECT
*
FROM
part AS normalPart
WHERE
normalPart.type = 'normal'
GROUP BY normalPart.partNumber , normalPart.genId) AS normalPart ON report.partNumber = normalPart.partNumber
AND report.genId = normalPart.genId
AND normalPart.cat = report.fromCat
LEFT JOIN
(SELECT
*
FROM
part AS premiumPart
WHERE
premiumPart.type = 'premium'
GROUP BY premiumPart.partNumber , premiumPart.genId) AS premiumPart ON report.partNumber = premiumPart.partNumber
AND report.genId = premiumPart.genId
AND premiumPart.cat = report.toCat;
Query Result
This answers the original version of the question.
Aggregate before you join:
select l.*, p.normal_price, p.premium_price
from (select genid, partnumber, sum(quantity) as quantity
from log
group by genid, partnumber
) l left join
(select partnumber, genid,
max(case when type = 'normal' then price end) as normal_price,
max(case when type = 'premium' then price end) as premium_price
from part
group by partnumber, genid
) p
on p.partnumber = l.partnumber and p.genid = l.genid
in barcodes table i have two column witch they are enter, exit like with student attendance record,
in this table when student entered to class, i add new row in table and enter value is 1 and exit is 0 like with login
after exiting from classroom i check latest row of this student and if enter is 1 then i add new row in table with 1 value for exit like with logout
now i want to calculate counting all students witch enter column is 1 and exit value is 0 to get all present students in class
SAMPLE DATA:
in this DB-FIDDLE i have sample data and into that i have 2 present student that session_id of them is 1, they are 123451,123452 students, but my sql command as second part is incorrect and that return one present student:
(
select count(*)
from barcodes b
where b.session_id = s.id
group by session_id, barcode
having sum(exit) = 0
) as present
for example:
select s.id, s.session_name, s.session_type, s.date_time,
(
select count(*)
from barcodes b where b.session_id = s.id
) as barcode_count ,
(
select count(*)
from barcodes b
where b.session_id = s.id
group by session_id, barcode
having sum(exit) = 0
) as present
from sessions s;
If I get what you want to do right, you can add another, outer aggregation.
...
(SELECT sum(x.count)
FROM (SELECT count(*) count
FROM barcodes b
WHERE b.session_id = s.id
GROUP BY b.session_id,
b.barcode
HAVING sum(b.enter) <> 0
AND sum(b.exit) = 0) x) present
...
But I think there's a much simpler way to get what you want by just taking the sum of enter minus exit for the session. Since any row with exit = 1 also comes with enter = 1, we need to double the exit before subtraction though.
...
(SELECT sum(b.enter - 2 * b.exit)
FROM barcodes b
WHERE b.session_id = s.id) present
...
If you can trust the data, something like this could work:
select
s.id,
s.session_name,
s.session_type,
s.date_time,
count(*) as barcode_count,
sum(exit = 0) - sum(exit = 1) as present
from sessions s
left join barcodes b on b.session_id = s.id
group by s.id, s.session_name, s.session_type, s.date_time
db-fiddle
You can read sum(exit = 0) - sum(exit = 1) as (number of entries) - (number of exits). If 4 students entered a class and 2 left the class, I would expect 2 students (4 - 2) to be still in the class.
I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state
I have database of following structure:
TABLE ingredients (ingredient_name, color)
TABLE recipes (recipe_name)
TABLE recipes_ingredients_parts (recipe_name, ingredient_name, parts)
What I want is to get a recipe that corresponds with selected ingredients and their number. So what I`ve tried first was query:
SELECT rr.* FROM
(SELECT r.* FROM receipes r
INNER JOIN receipes_ingredients_parts ri
ON r.receipe_name = ri.receipe_name
AND ri.ingredient_name = 'espresso'
AND ri.parts_number = '1') rr;
And what I get are {"Americano", "Espresso"}. But that should be "Espresso" only because for "Americano" there should be the query:
SELECT rr.* FROM
(SELECT r.* FROM receipes r
INNER JOIN receipes_ingredients_parts ri
ON r.receipe_name = ri.receipe_name
AND ri.ingredient_name = 'espresso'
AND ri.parts_number = '1') rr
INNER JOIN receipes_ingredients_parts ri
ON rr.receipe_name = ri.receipe_name
AND ri.ingredient_name = 'water'
AND ri.parts_number = '4';
Next my idea was to alter recipe table and add columns for each ingredient to store it's quantity for the recipe. But it would be near 20 columns of that kind. So I'm confused with thought that I'm doing job in a bad style. Maybe I should use some good query for the purpose? Do you guys have any ideas about all the stuff?
I think this is what you are looking for, it should find receipe_names that have all the ingredients in your list, and no other ingredients.
SELECT receipe_name
, SUM(CASE
WHEN (ingredient_name, parts_number) IN (('espresso','1'))
THEN 1 ELSE 0
END
) AS matchedIngredients
, SUM(CASE
WHEN (ingredient_name, parts_number) NOT IN (('espresso','1'))
THEN 1 ELSE 0
END
) AS otherIngredients
FROM receipes_ingredients_parts
GROUP BY receipe_name
HAVING matchedIngredients = 1 AND otherIngredients = 0
A more generalized version/template:
SELECT aField
, SUM(CASE
WHEN someField IN ([matchList])
THEN 1
ELSE 0
END
) AS matches
, SUM(CASE
WHEN someField NOT IN ([matchList])
THEN 1
ELSE 0
END
) AS others
FROM aTable
GROUP BY aField
HAVING matches = [# of values in matchlist]
AND others = 0
Alternatively, if items in the matchlist might be repeated in the table for an "aField" value:
SELECT aField
, COUNT(DISTINCT CASE
WHEN someField IN ([matchList])
THEN someField
ELSE NULL
END
) AS matches
, COUNT(DISTINCT CASE
WHEN someField NOT IN ([matchList])
THEN someField
ELSE NULL
END
) AS others
FROM aTable
GROUP BY aField
HAVING matches = [# of values in matchlist]
AND others = 0
i have a table with data title and date of the data inserted.
and right now i want to do count to make the statistic out of it.
can i do multiple count in one sql statement?
like from, the column date, i want to count how many on this month, and how many in this year, until month selected. is it possible? if yes, how?
this is what i have come up, for now.
SELECT a.trigger_type_code
, c.trigger_name
, COUNT(*) AS number
FROM issue_trigger a
INNER JOIN cs_issue b
ON b.issue_id = a.issue_id
INNER JOIN ref_trigger_type c
ON c.trigger_type_code = a.trigger_type_code
WHERE MONTH(b.created_date) = '05'
AND YEAR(b.created_date) = '2011'
GROUP BY trigger_type_code,trigger_name
by this is only for one count.help.:(
You could use a case:
select sum(case when MONTH(b.created_date) = '05'
AND YEAR(b.created_date) = '2011' then 1 end) as Count_2011_05
, sum(case when YEAR(b.created_date) = '2011'
then 1 end) as Count_2011
from ... etc ...
I think you could go like this:
SELECT
a.trigger_type_code,
c.trigger_name,
COUNT(MONTH(b.created_date) < 5 OR NULL) AS before_the_month,
COUNT(MONTH(b.created_date) = 5 OR NULL) AS in_the_month
FROM issue_trigger a
INNER JOIN cs_issue b
ON b.issue_id = a.issue_id
INNER JOIN ref_trigger_type c
ON c.trigger_type_code = a.trigger_type_code
WHERE YEAR(b.created_date) = 2011
GROUP BY a.trigger_type_code, c.trigger_name