mSSQL, SQL view, select, percentage query - sql

So this is the requirement I need to meet:
Aggregated data of all the schools in the ESD, grouped by
SchoolDistrict.SchoolDistrictID
(get the same data as the school district scenario above, then add grouping by district, filtered to
EducationServiceDistrict. EducationServiceDistrictID
)
Also calculate percentage of pass, fail, and untested
How do I calculate the percentage pass, fail, and untested?
This is the query I have written so far.
CREATE VIEW district_map AS
SELECT * and SchoolDistrictID,
EducationServiceDistrict
FROM SchoolDistrict_View
and SchoolDistrict,
EducationServiceDistrict
GROUP BY EducationServiceDistrict.EducationServiceDistrictID
ORDER BYLeadWaterTestLocation.PassFail

This is the general idea of how these problems are solved - if you understand this simplified version you will be able to solve your problem.
select d.districtName,
s.studentCount,
case when s.studentCount=0 then 0 else s.passed / s.studentCount * 100 end as PassedPct
from district d
join (select districtId,
sum(studentCount) as studentCount,
sum(passed) as passed
from schools
group by districtId) as s
on d.districtId = s.districtId
order by d.districtName

Related

SQL query to return average of results using JOIN and GROUP BY

I have a simple manufacturing job card system that track parts and labor for an assigned job.
It consists of a JobHeader table that holds the Job Card number (JobHeader.JobNo), ID of the part being manufactured (JobHeader.RegNo) and quantity to be manufactured (JobHeader.RegNo).
There is a child table (JobLabour) that tracks all the times that have been worked on the job (JobLabour.WorkedTime)
I'm looking for a query that will return the average time taken to produce a part accross the last 5 job cards for that particular part.
The following query
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime FROM JobHeader INNER JOIN JobLabour ON JobHeader.JobNo=JobLabour.JobNo
WHERE JobHeader.RegNo='RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
will return this:
But what I'm looking for is a query that will return the average BOMQty and average totalTime. Something like this:
Is there a way to do this?
Your question explicitly mentions the "last five" but does not specify how that is determined. Presumably, you have some sort of date/time column in the data that defines this.
In SQL Server, you can use apply:
select jh.*, jl.*
from jobheader jh outer apply
(select top (5) avg(BOMQty) as avg_BOMQty, avg(totalTime) as avg_totalTime
from (select top (5) jl.*
from joblabour jl
where jl.regno = jh.regno
order by jl.<some datetime> -- however you determine the last five
) jl
) jl;
You can add a where clause to the outer query to filter on one or more particular jobs.
If I understand you correctly this will do the work
this will work for 1 RegNo='RM-BRU-0134' at a time
with topFive as (
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime
FROM JobHeader
INNER JOIN JobLabour ON JobHeader.JobNo = JobLabour.JobNo
WHERE JobHeader.RegNo = 'RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
)
select RegNo, avg(BOMQty) as BOMQty, avg(TotalTime) as TotalTime
from topFive
group by RegNo

Select only the row with the max value, but the column with this info is a SUM()

I have the following query:
SELECT DISTINCT
CAB.CODPARC,
PAR.RAZAOSOCIAL,
BAI.NOMEBAI,
SUM(VLRNOTA) AS AMOUNT
FROM TGFCAB CAB, TGFPAR PAR, TSIBAI BAI
WHERE CAB.CODPARC = PAR.CODPARC
AND PAR.CODBAI = BAI.CODBAI
AND CAB.TIPMOV = 'V'
AND STATUSNOTA = 'L'
AND PAR.CODCID = 5358
GROUP BY
CAB.CODPARC,
PAR.RAZAOSOCIAL,
BAI.NOMEBAI
Which the result is this. Company names and neighborhood hid for obvious reasons
The query at the moment, for those who don't understand Latin languages, is giving me clients, company name, company neighborhood, and the total value of movements.
in the WHERE clause it is only filtering sales movements of companies from an established city.
But if you notice in the Select statement, the column that is retuning the value that aggregates the total amount of value of sales is a SUM().
My goal is to return only the company that have the maximum value of this column, if its a tie, display both of em.
This is where i'm struggling, cause i can't seem to find a simple solution. I tried to use
WHERE AMOUNT = MAX(AMOUNT)
But as expected it didn't work
You tagged the question with the whole bunch of different databases; do you really use all of them?
Because, "PL/SQL" reads as "Oracle". If that's so, here's one option.
with temp as
-- this is your current query
(select columns,
sum(vrlnota) as amount
from ...
where ...
)
-- query that returns what you asked for
select *
from temp t
where t.amount = (select max(a.amount)
from temp a
);
You should be able to achieve the same without the need for a subquery using window over() function,
WITH T AS (
SELECT
CAB.CODPARC,
PAR.RAZAOSOCIAL,
BAI.NOMEBAI,
SUM(VLRNOTA) AS AMOUNT,
MAX(VLRNOTA) over() AS MAMOUNT
FROM TGFCAB CAB
JOIN TGFPAR PAR ON PAR.CODPARC = CAB.CODPARC
JOIN TSIBAI BAI ON BAI.CODBAI = PAR.CODBAI
WHERE CAB.TIPMOV = 'V'
AND STATUSNOTA = 'L'
AND PAR.CODCID = 5358
GROUP BY CAB.CODPARC, PAR.RAZAOSOCIAL, BAI.NOMEBAI
)
SELECT CODPARC, RAZAOSOCIAL, NOMEBAI, AMOUNT
FROM T
WHERE AMOUNT=MAMOUNT
Note it's usually (always) beneficial to join tables using clear explicit join syntax. This should be fine cross-platform between Oracle & SQL Server.

CTEs count and sum

I am trying to get the sum of the count I did on "cll.Claim_number" column.The below CTE is part of 3 othe CTEs and the CTEs run perfectly but now I want to only bring in the "sum" of "COUNTOFSERVICES" from the count I did on cll.Claim_number. I want the output field to have only the sum with the rest of the fields I call out that's it not the count. Below is what I have but it gives both the count and sum in the output when I only want the sum . Thanks
Select
cll.company_desc as state,
cll.line_of_business_desc as Lineofbus,
cll.product_desc as Product,
cll.paymentdate as YearMonth,
cll.typeofservice,
prt.prov_type_short_desc as ProviderSpecialty,
cll.whole_claim_status_desc as Outcome,
count(cll.Claim_number) as "COUNTOFSERVICES",
sum(cll.Claim_number) as total
from claims cll
left join dw.DIM_PROVIDER_TYPE prt -- bringing in provider spec from claim
on cll.prov_type_dim_id = prt.prov_type_dim_id
Where cll.uniquerow = '1'--dedupping
Group By
cll.company_desc,
Cll.line_of_business_desc,
cll.product_desc,
cll.paymentdate,
--cll.memb_dim_id,
cll.typeofservice,
prt.prov_type_short_desc,
cll.whole_claim_status_desc,
cll.Claim_number
Thanks #jarlh
I removed the cll.claimnumber from Group and did the below and I got exactly what I was looking for . I also removed the sum since the count did exactly what I wanted after removing the claimnumber from GROUP.
Providers as (
Select
cll.company_desc as state,
cll.line_of_business_desc as Lineofbus,
cll.product_desc as Product,
cll.paymentdate as YearMonth,
cll.typeofservice,
prt.prov_type_short_desc as ProviderSpecialty,
cll.whole_claim_status_desc as Outcome,
count(cll.Claim_number) as "COUNTOFSERVICES"
--sum(cll.Claim_number) as total --removed
from claims cll
left join dw.DIM_PROVIDER_TYPE prt -- bringing in provider spec from claim
on cll.prov_type_dim_id = prt.prov_type_dim_id
Where cll.uniquerow = '1'--dedupping
Group By
cll.company_desc,
Cll.line_of_business_desc,
cll.product_desc,
cll.paymentdate,
--cll.memb_dim_id,
cll.typeofservice,
prt.prov_type_short_desc,
cll.whole_claim_status_desc
) select * from providers

PSQL: sum doesn't work on fields

I have this query which works:
SELECT
partners.name,
roles.name,
(SELECT count(*) FROM partner_member_bindings WHERE roles.id = partner_member_bindings.role_id AND verify_status != 'pending') AS Num_verifications,
CAST(roles.price_partner / 100 AS money) AS partner_price
FROM partners
JOIN roles ON roles.partner_id = partners.id
ORDER BY partners.name, roles.name
What I want is to display an additional field showing the "partner_price * Num_verifications" value in dollars. Nothing I do works:
sum(Num_verifications * partner_price) returns that the Num_verification doesn't exist. Copying over the whole sub-query (yes, i know, but I'm just testing) also doesn't work.
How can this be done?
The fields in select can only contain input columns and they become output columns when they are run. That is why you cannot use a computed column in another column definition.
But if you want a SUM that would mean some kind of aggregation. If you want the total sum of the multiplication of the fields, that is not usually done per row. Or do you only need the multiplication result? That is usually done in the presentation layer.
If you only need the multiplication (since there is no GROUP BY the SUM would be that anyway) you can put the whole query into a subquery and calculate from that, leaving the sorting outside:
SELECT
partnername,
rolename,
Num_verifications,
partner_price,
partner_price*Num_verifications
FROM
(SELECT
partners.name as partnername,
roles.name as rolename,
(SELECT count(*) FROM partner_member_bindings WHERE roles.id = partner_member_bindings.role_id AND verify_status != 'pending') AS Num_verifications,
CAST(roles.price_partner / 100 AS money) AS partner_price
FROM partners
JOIN roles ON roles.partner_id = partners.id) temp
ORDER BY partners.name, roles.name

How do you explicitly show rows which have count(*) equal to 0

The query I'm running in DB2
select yrb_customer.name,
yrb_customer.city,
CASE count(*) WHEN 0 THEN 0 ELSE count(*) END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid and yrb_member.club like '%Club%'
group by yrb_customer.name, yrb_customer.city order by count(*)
Shows me people which are part of clubs which has the word 'Club' in it, and it shows how many such clubs they are part of (#UniClubs) along with their name and City. However for students who are not part of such a club, I would still like for them to show up but just have 0 instead of them being hidden which is what's happening right now. I cannot get this functionality with count(*). Can somebody shed some light? I can explain further if the above is not clear enough.
I'm not familiar with DB2 so I'm taking a stab in the dark, but try this:
select yrb_customer.name,
yrb_customer.city,
CASE WHEN yrb_member.club like '%Club% THEN count(*) ELSE 0 END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid
group by yrb_customer.name, yrb_customer.city order by count(*)
Basically you don't want to filter for %Club% in your WHERE clause because you want ALL rows to come back.
You're going to want a LEFT JOIN:
SELECT yrb_customer.name, yrb_customer.city,
COUNT(yrb_member.club) as clubCount
FROM yrb_customer
LEFT JOIN yrb_member
ON yrb_member.cid = yrb_customer.cid
AND yrb_member.club LIKE '%Club%
GROUP BY yrb_customer.name, yrb_customer.city
ORDER BY clubCount
Also, if the tuple (yrb_customer.name, yrb_customer.city) is unique (or is supposed to be - are you counting all students with the same name as the same person?), you might get better performance out of the following:
SELECT yrb_customer.name, yrb_customer.city,
COALESCE(club.count, 0)
FROM yrb_customer
LEFT JOIN (SELECT cid, COUNT(*) as count
FROM yrb_member
WHERE club LIKE '%Club%
GROUP BY cid) club
ON club.cid = yrb_customer.cid
ORDER BY club.count
The reason that your original results were being hidden was because in your original query, you have an implicit inner join, which of course requires matching rows. The implicit-join syntax (comma-separated FROM clause) is great for inner (regular) joins, but is terrible for left-joins, which is what you really needed. The use of the implicit-join syntax (and certain types of related filtering in the WHERE clause) is considered deprecated.