I have a SQL query that returns to me a list of Analysts with amount of claims they've filed and the amount. I know how many Analyst there are for a specific client (6). The problem I'm having is when I run the query, only 4 pop up. If i comment out the WHERE clause (which gives me back each Analysts specific amount), I get all the Analyst, but their amounts are all the same. How do I get back the missing Analysts? I don't care if they return 0... as a matter of fact, that's what i'm trying to figure out along with the count and sums. All help is greatly appreciated. Here's my code:
SELECT
a.auditorID,
fName,
COUNT(DISTINCT case when claims.dateon >='20200726' AND claims.dateon <= '20200909' AND entries.errorCode NOT IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then claims.rID end) as rTotal1,
SUM(case when claims.dateon >= '20200726' AND claims.dateon <= '20200909' AND entries.errorCode NOT IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then entries.refundDue else 0.0 end) as rate1,
COUNT(DISTINCT case when claims.dateon >='20200726' AND claims.dateon <= '20200909' AND entries.errorCode IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then claims.rID end) as pTotal1,
SUM(case when claims.dateon >= '20200726' AND claims.dateon <= '20200909' AND entries.errorCode IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then entries.refundDue else 0.0 end) as payment1
FROM auditors a
INNER JOIN
(
SELECT auditorID, assignments.clientID FROM assignments INNER JOIN assignmentCarriers ac ON ac.acID=Assignments.acID WHERE isAssignment='True' GROUP BY auditorID, assignments.clientID
) tAssignments ON tAssignments.auditorID=a.auditorID
INNER JOIN
(
SELECT clientID, code FROM clients WHERE code='ABBL'
) tClients ON tClients.clientID=tAssignments.clientID
INNER JOIN claims ON claims.client=tClients.code
INNER JOIN entries ON claims.rID = entries.rid
WHERE claims.auditorID=a.auditorID
GROUP BY a.auditorID, fName
ORDER BY fName
Here's what I'm getting when I run the code without the SUM or COUNT...
98 User 1
99 User 2
21 User 3
61 User 4
103 User 5
172 User 6
Here's with the constraints
98 User 1 17 147346.3000 1 9451.1600
21 User 2 0 0.0000 21 182958.5100
61 User 3 5 36970.0000 81 353592.8000
103 User 4 534 319697.5774 58 234350.7900
Related
Select p.pnum,
SUM(CASE WHEN P.NegativeScreen = 'Type99' THEN 1 ELSE 0 END) TotalDetected,
SUM(IIF(P.IsPositive = 1, 1,0)) TotalP,
SUM(CASE WHEN (P.MethId NOT IN (4, 8, 10, 25) THEN 1 ELSE 0 END) Total,
SUM(CASE WHEN (P.MethID IN (34,64) ) THEN 1 ELSE 0 END) TotalVal1,
SUM(CASE WHEN (P.MethID IN (16,64) ) THEN 1 ELSE 0 END) TotalVal2,
SUM(CASE WHEN (P.MethID IN (2,4,6,11,13,14,15,18,21,22,24,28,30,31) OR (P.MethID
= 1 AND P.TotalCount IS NOT NULL)) THEN 1 ELSE 0 END) TotalMethOther,
FROM tbl_plt p
GROUP BY P.PNum
Notice that the above query has all the fields from the tbl_plt table and SUM() is done on the fields.
Notice where I have MethID mentioned above. I need to check if those MethID exist in the tbl_plt table and if they exist in another table called TblOther. If so, tally it up accordingly.
Here is the fields in TblOther Table. Note that in TblOther table, we can have multiple PNums but the MethID will be different. Also note that for not all pNums will have entries in the TblOther table.
ID PNum MethID
1 232 32
2 232 64
3 232 10
4 104 14
5 104 54
6 22 4
7 4 13
I tried with LEFT JOIN with TblOther table but things gets messy as with the left join, it also tallies up incorrectly for places like:
SUM(CASE WHEN P.NegativeScreen = 'Type99' THEN 1 ELSE 0 END) TotalDetected,
SUM(IIF(P.IsPositive = 1, 1,0)) TotalP,
As an example for where I have:
SUM(CASE WHEN (P.MethID IN (34,64) ) THEN 1 ELSE 0 END)
it needs get the count of how many MethID exist in both the tblOther and tbl_plt for where MethID is 34 or 64 for the associated PNum.
It needs to do similarly for other places where MethID is mentioned.
I don't know enough about TblOther or it's join, but I suspect you might need to do the same group by (i.e., PNum) on it before joining on PNum. Then the left join will match either 0 or 1 records. Be sure to account for the null if there is no match.
You could start by getting the list of distinct PNum and MethIDs to use and then do your summing based on that list:
;WITH entries as (
SELECT DISTINCT PNum, MethID
FROM tblOther)
SELECT *
FROM entries
INNER JOIN tbl_plt
ON entries.PNum = tbl_plt.PNum
AND entries.MethID = tbl_plt.MethID
GROUP BY entries.PNum
I have a Cab transport application
Each driver has a Trip and for each trip, there can be multiple customers (Cab pooling) giving their feedback.
Now I want to get the drivers of those drivers who got more than 10 five star ratings(5*) and a minimum of 20% Five-star ratings out of their total Ratings received from their customers.
Let's say a driver got a total 40 feedbacks in the last 30 days out of which 16 are 5-star ratings, then this driver has met the criteria of minimum 10 5* star ratings and more than 20% 5* ratings. This driver id should be fetched.
SELECT TR.[DriverId]
,100.0 * AVG(CASE
WHEN FE.[Rating] = 5
THEN 1.0
ELSE 0
END) AS Percentage
FROM tblFeedback FE
LEFT OUTER JOIN tblTrip TR ON FE.TripId = TR.TripId
WHERE FE.DATE >= GETDATE() - 30
AND FE.Rating = 5
GROUP BY DriverId
HAVING COUNT(CASE
WHEN FE.[Rating] = 5
THEN DriverId
END) >= 10
AND 100 * AVG(CASE
WHEN FE.[Rating] = 5
THEN 1.0
ELSE 0
END) > 20
The above query is showing the Percentage as 100.000 for all the Drivers whose Id's are fetched, even those drivers whose total percentage is 18% are also fetched and their percentage is shown as 100%.
This query has screwed my report completely
Try this. You need to include all the ratings in order to calculate the percentage:
SELECT r.[DriverId], 100.0*r.five_stars/r.total_ratings AS Percentage
FROM (
SELECT TR.[DriverId]
SUM(CASE WHEN FE.Rating =5 THEN 1 ELSE 0 END) AS five_stars,
SUM(*) AS total_ratings
FROM tblFeedback FE
INNER JOIN tblTrip TR ON FE.TripId = TR.TripId
WHERE FE.DATE >= GETDATE() - 30
GROUP BY TR.DriverId) r
WHERE r.five_stars>=10
AND 100.0*r.five_stars/r.total_ratings>20.0;
I think the issue is in your WHERE clause. This line in particular:
AND FE.Rating = 5
This is forcing the tblFeedback table to only return records that have a five-star rating, and therefore, only the five-star ratings are used in the calculation. Try taking that line out and see if the calculations are any closer to what you expect.
This is the code I have
select distinct sli.order_no,
sli.pkg_no,
case when line.primary_ind = 'Y' then sum(paid_amt) else 0 end as paid_amt,
line.pkg_li_no,
sum(case when sli.perf_no = 0 then 1 else 0 end) as num_seats_pur,
sli.status
from t_sub_line sli
left outer join t_line line on sli.li_seq_no = line.li_seq_no
where sli.order_no in (1,2)
group by
sli.order_no,
sli.pkg_no,
line.primary_ind,
line.pkg_li_no,
sli.status
having line.primary_ind = 'Y'
This code produces this output
order_no pkg_no paid_amt pkg_li_no num_seats_pur status
1 322 124.00 967 2 7
1 322 -124.00 992 2 4
2 854 253.00 952 1 7
2 854 -253.00 996 1 4
what I really need for the data to return is the following. I need the sum of paid_amt field.
order_no pkg_no paid_amt pkg_li_no num_seats_pur status
1 322 0 967 2 7
2 854 0 996 1 4
even if i change status to be max(status) so its not grouping on it. I don't have sum_paid amt.
when i try this code:
sum(case when line.primary_ind = 'Y' then sum(paid_amt) else 0 end) as paid_amt,
I get the following error message
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
A couple things you need to do.
Comment out pkg_li_no from the select and group by
Change the having statement to be included in the where statement
Remove the case from paid_amt since it is not necessary
select distinct sli.order_no,
sli.pkg_no,
sum(paid_amt)as paid_amt,
-- line.pkg_li_no,
sum(case when sli.perf_no = 0 then 1 else 0 end) as num_seats_pur,
sli.status
from t_sub_line sli
left join t_line line on sli.li_seq_no = line.li_seq_no
where sli.order_no in (1,2)
and line.primary_ind = 'Y'
group by
sli.order_no,
sli.pkg_no,
line.primary_ind,
-- line.pkg_li_no,
sli.status
Other notes:
I am not sure you want to select or group by the pkg_no or status, but you know more what outcome are looking for. If they are different values, there will be different records.
I'm not sure what you're trying to accomplish, but it seems that you overthinking the query. Try to simplifying it.
FYI HAVING happens after the grouping, WHERE happens before the grouping, you don't even need the CASE
select distinct sli.order_no,
sli.pkg_no,
sum(paid_amt) as paid_amt,
sum(case when sli.perf_no = 0 then 1 else 0 end) as num_seats_pur,
sli.status
from t_sub_line sli
left outer join t_line line on sli.li_seq_no = line.li_seq_no
where sli.order_no in (1,2)
and line.primary_ind = 'Y'
group by
sli.order_no,
sli.pkg_no,
sli.status
I need to produce the number of healthclub members that are enrolled through their employer(several different employers not just 1) for a monthly membership and what level of membership they have plus their family members. The problem I am having is that currently we do not have any LEVEL D membership but may in the future. I need the report to display ‘0’ when there is no membership. I tried
COUNT(DISTINCT CUSTOMER_ID) +
COUNT(CASE WHEN CUSTOMER_ID IS NULL THEN 1 END) AS NUMBER_OF_CUSTOMERS
And it did not work, any help is appreciated.
SELECT
MEMBERSHIP_TYPE,
COUNT(DISTINCT CUSTOMER_ID) AS NUMBER_OF_CUSTOMERS,
COUNT(CASE WHEN CUSTOMER_RELATION = ‘FAMILYMEMBER’ THEN 1 END) AS FAMILY_MEMBERS,
COUNT(DISTINCT CUSTOMER_ID) + COUNT(CASE WHEN CUSTOMER_RELATION ‘FAMILY_MEMBERS’ THEN 1 END) AS TOTAL
This is what I currently get
MEMBERSHIP_TYPE NUMBER_OF_CUSTOMERS FAMILY_MEMBERS TOTAL
-------------------------------------------------------------
LEVEL A 100 25 125
LEVEL B 630 340 970
LEVEL C 1201 630 1831
I need this
MEMBERSHIP_TYPE NUMBER_OF_CUSTOMERS FAMILY_MEMBERS TOTAL
-------------------------------------------------------------
LEVEL A 100 25 125
LEVEL B 630 340 970
LEVEL C 1201 630 1831
LEVEL D 0 0 0
You will hardcode the value into the select statement. Add a UNION ALL to the SQL statement
..your current select statement
UNION
SELECT LEVEL D, 0,0,0;
When an entry of Level D will be made in the table, the updated value will be shown correctly.
Here's a tricky problem I haven't quite been able to get my head around. I'm using SQL Server 2008, and I have a sparse range table that looks like this:
Range Profession
----- ----------
0 Office Worker
23 Construction
54 Medical
Then I have another table with values that are within these ranges. I'd like to construct a query which joins these two tables and gives me the Profession value that is less than or equal to the given value. So let's say my other table looks like this:
Value
29
1
60
Then I'd like my join to return:
Value Profession
----- ----------
29 Construction
1 Office Worker
60 Medical
(because 29>the 23 for Construction but <=the 54 for Medical)
Is there any way I can get SQL to bend to my will in this manner, short of actually blowing out the range table to include every possible value?
Thank you.
Easist Way to do this is to add a another column to you sparse range table.
LowRange HighRange Profession
0 22 Office Worker
23 53 Construction
54 999999 Medical
Then use a query like this to get the range(table 2 is the one with the 29,1,60 values):
SELECT Table_2.JoinKey as Value, Table_1.Description as Profession
FROM Table_1 INNER JOIN Table_2
ON Table_2.JoinKey => Table_1.LowRangeKey
AND Table_2.JoinKey <= Table_1.HighRangeKey;
You could use CROSS APPLY:
select v.Value, p.Profession
from tblValues v
cross apply
(select top(1) pr.Profession
from tblProfessionRanges pr
where pr.Range <= v.Value ORDER BY pr.[Range] DESC) p
It should be faster than using max and doesn't need a max-range do be maintained.
I think I understand your problem. I created a table called professions with your values and a map_vals table with the look up values. Then I came up with this:
select p.range as `range1`, p.profession, v.value from professions p
inner join map_vals v ON v.value >= p.range
where p.range =
(select max(p3.range) from professions p3 where p3.range <= v.value)
order by v.value
which when given these values...
value
29
0
60
1
23
54
returns
range1 profession value
0 Office Worker 0
0 Office Worker 1
23 Construction 23
23 Construction 29
54 Medical 54
54 Medical 60
EDIT:
You could also use CROSS APPLY as shown by manfred-sorg but it requires an ORDER BY DESC or you will get the following:
select v.Value, p.Profession
from tblValues v
cross apply
(select top(1) pr.Profession
from tblProfessionRanges pr
where pr.Range <= v.Value) p
produces
Value Profession
----------- --------------------------------------------------
29 Office Worker
1 Office Worker
60 Office Worker
to get your desired result you need to change it to:
select v.Value, p.Profession
from tblValues v
cross apply
(select top(1) pr.Profession
from tblProfessionRanges pr
where pr.Range <= v.Value ORDER BY pr.[Range] DESC) p
Value Profession
----------- --------------------------------------------------
29 Construction
1 Office Worker
60 Medical
However, the sorting required here makes it less efficient than using MAX.