Change the value of a sum in sql - sql

I'm doing a query to obtain the numbers of people for a Christmas dinner.
The people include the workers and their relatives. The relatives are stored in a different table.
Children and adults eat a different menu and we organize tables by families.
I'm already using this query
select worker_name,
count(*) as total_per_family,
SUM(CASE WHEN age < 18 THEN 1 ELSE 0 END) as children,
SUM(CASE WHEN age >= 18 THEN 1 ELSE 0 END) as adults
from
(
/*subquery*/
)
group by worker_name
order by worker_name;
This query returns the number of child and adults related to the worker and count gives me the total.
The problem is that I need to add the worker to the adults sum.
Is there a way to modify adults? Either setting its initial value to 1 or adding 1 after the sum is done but before the count is obtained.

Modifying your query to read
SUM(CASE WHEN AGE>=18 THEN 1 ELSE 0 END) + 1 as adults
would probably be a first approach. The aggregate SUM() would be computed first, with 1 added thereafter as your initial suggestion indicated.

Related

Complex SQL query to combine rows

I have 2 tables first is
Thread { code, itr_global,campaign, contact, start_time,duration}
segment {code,thread,start_time,duration,state}
There are multiple other joins but these 2 are major joins. 2 table are realted as thread.code=segment.thread.
In segment table there will be multiple rows for singl thread. I need to get values
campaign start_time duration waititme talk_time hold_time wrap_time
Where wait_time I can get as segment.state=7 & talke_time=segment.state=6 & wrap time as segment.state=8
I am not able to get all these values in single row as it will give me 3 diffrent rows for each record. How can I get all the values in single row as per above format.
You need some conditional aggregation SUM(CASE...) to get the result you want.
All this is based on my guesses about the structure and meaning of your tables, which you omitted from your question.
SELECT thread.code, thread.campaign,
SUM(segment.duration) duration,
SUM(CASE WHEN segment.state = 7 THEN segment.duration END) waittime,
SUM(CASE WHEN segment.state = 6 THEN segment.duration END) talk_time,
SUM(CASE WHEN segment.state = 8 THEN segment.duration END) wrap_time,
42 hold_time, -- you didn't say how to get hold_time
SUM(CASE WHEN segment.state = 8 THEN segment.duration END) wrap_time
FROM Thread
LEFT JOIN segment ON Thread.code = segment.thread
GROUP BY thread.code, thread.campaign

Loop Back to Same Table

Is there a way to combine these two queries into a single query - just one trip to the database?
Both queries hit the same table, but the first is looking for Total Active Circuits, while the second is looking for Total Circuits.
I am hoping to display results like this...
4/15, 12/34, 2/21 (where the first number is ActiveCircuits and the second number is TotalCircuits)
SELECT COUNT(CircuitID) AS ActiveCircuits
FROM Circuit
WHERE StateID = 5
AND Active = 1
SELECT COUNT(CircuitID) AS TotalCircuits
FROM Circuit
WHERE StateID = 5
Use conditional aggregation:
SELECT COUNT(*) AS TotalCircuits,
SUM(CASE WHEN Active = 1 THEN 1 ELSE 0 END) as ActiveCircuits
FROM Circuit
WHERE StateID = 5;
This assumes that CircuitId is never NULL, which seems quite reasonable in a table called Circuit.
You can use case when to have a 1 wherever it's active and then take the sum to get the total # of 1's or activecircuits.
SELECT COUNT(CIRCUITID) AS TOTALCIRCUITS,
SUM(CASE WHEN ACTIVE = 1 THEN 1 ELSE 0 END) AS ACTIVECIRCUITS
FROM CIRCUIT
WHERE STATEID = 5

Issue with case when SQL

I have a table named 'candidate' which contains among others columns ,score_math' and 'score_language' reflecting candidate's score in respective tests. I need to
Show the number of students who scored at least 60 in both math and language (versatile_candidates) and the number of students who scored below 40 in both of
these tests (poor_candidates). Don't include students with NULL preferred_contact. My query is:
select
count(case when score_math>=60 and score_language>=60 then 1 else 0
end) as versatile_candidates,
count(case when score_math<40 and score_language<40 then 1 else 0 end) as
poor_candidates
from candidate
where preferred_contact is not null
But this produces always total number of candidates wit not-null preferred contact type. Can't really figure out what I did wrong and more importantly why this doesn't work. [DBMS is Postgres if this matters ]Please help
You're close - the reason you're getting the total number of all candidates is because COUNT() will count a 0 the same as a 1 (and any other non-NULL value, for that matter). And since the values could only ever be 0 or 1, your COUNT() will return the total number of all candidates.
Since you're already defaulting the cases that don't match to 0, all you need to do is change the COUNT() to a SUM():
Select Sum(Case When score_math >= 60
And score_language >= 60 Then 1
Else 0
End) As versatile_candidates
, Sum(Case When score_math < 40
And score_language < 40 Then 1
Else 0
End) As poor_candidates
From candidate
Where preferred_contact Is Not Null
COUNT() does not take into consideration NULL values. All other values which are not NULL will be counted.
You might want to replace it with SUM()

Count where conditions are different

I've been trying to optimize one of my more bulky db views.
Presently, I'm just using sub-selects 5 times to get the count of the company ID's.
(Select count(id) from company table where prospecting.stage = 'qualify') as Qualify,
(Select count(id) from company table where prospecting.stage = 'targetted') as Targetted,
Each company goes through 5 stages, I simply want to count the amount of companies in each stage by company location in separate columns.
I'm trying to do this in one select, but I am getting a bit stuck.
SUM(COUNT(CASE WHEN prospecting.stage = 'Qualify' THEN '1' ELSE '0' END)) as [Qualified]
SUM(COUNT(CASE WHEN prospecting.stage = 'Targetted' THEN '1' ELSE '0' END)) as [Targetted]
So it ends up looking something along these lines:
Location | Stage: Qualify | Stage: Targetted | Stage 3 | Stage 4 | Stage 5 | Total
Cannot perform an aggregate function on an expression containing an aggregate or a subquery. -Makes sense.
So I need to count the Company.ID where the prospecting.stage = 'XYZ' into separate rows per stage.
Any advice? :(
Drop the count function and change the datatype from char to int in the case expressions. Your expressions should look like this:
SUM(CASE WHEN prospecting.stage = 'Qualify' THEN 1 ELSE 0 END) as [Qualified]

Counting non-zero values in sql

I am trying to count total number of times that each individual column is greater than zero, grouped by the driver name. Right now I have;
SELECT drivername
, COUNT(over_rpm) AS RPMViolations
, COUNT(over_spd) AS SpdViolations
, COUNT(brake_events) AS BrakeEvents
FROM performxbydriverdata
WHERE over_rpm > 0
OR over_spd > 0
OR brake_events > 0
GROUP BY drivername
This gives me all of the non-zero values but I get a display as:
Bob Smith 62 62 62
Nathan Jones 65 65 65
etc.
I'm trying to get a count of non-zeros in each individual values.. each violation should be grouped separately.
Use NULLIF to change zero to NULL, count ignores NULL
SELECT drivername,
COUNT(NULLIF(over_rpm,0)) AS RPMViolations,
COUNT(NULLIF(over_spd,0)) AS SpdViolations,
COUNT(NULLIF(brake_events,0)) AS BrakeEvents
FROM performxbydriverdata
GROUP BY drivername;
You can probably remove the WHERE clause too with this group to improve performance
OR conditions often run badly because of matching a good index
Using HAVING (as per other answers) will remove any rows where all 3 aggregates are zero which may or may not be useful for you. You can add this if you want. Saying that, the WHERE implies that at least one row has non-zero values so you don't need both WHERE and HAVING clauses
Putting filter predicate[s] inside of a Sum() function with a case statement is a useful trick anytime you need to count items based on some predicate condition.
Select DriverName,
Sum(case When over_rpm > 0 Then 1 Else 0 End) OverRpm,
Sum(case When over_spd > 0 Then 1 Else 0 End) OverSpeed,
Sum(case When brake_events > 0 Then 1 Else 0 End) BrakeEvents,
etc.
FROM performxbydriverdata
Group By DriverName