Sum() slows down my query - mysql

I am using sum() inside case statement. But this slows down my query. Is there any other way for this. This is the query. Please help me.
SELECT (SUM(PRI_INS_AGING) + SUM(SEC_INS_AGING) + SUM(TER_INS_AGING)) AS INS_AGING,SUM(PAT_AGING) AS PAT_AGING FROM
(SELECT
CASE WHEN L.RESP_PARTY =1 AND VP.STATUS IN(3,5) AND VP.PRIMARY_PAID =0 AND VP.PRIMARY_PENDING >0 AND C.PRIMARY_PAYER_ID >0 AND C.HIDEN=0 THEN SUM(L.AMOUNT) ELSE 0 END AS PRI_INS_AGING,
CASE WHEN L.RESP_PARTY =2 AND VP.STATUS IN(6,7,5) AND VP.SECONDARY_PAID =0 AND VP.SECONDARY_PENDING >0 AND VP.PRIMARY_PENDING <=0 AND C.SECONDARY_PAYER_ID >0 AND C.HIDEN=0 THEN SUM(L.AMOUNT) ELSE 0 END AS SEC_INS_AGING,
CASE WHEN L.RESP_PARTY =3 AND VP.STATUS IN(8,9,5) AND VP.TERTIARY_PAID =0 AND VP.TERTIARY_PENDING >0 AND VP.PRIMARY_PENDING <=0 AND VP.SECONDARY_PENDING <=0 AND C.TERTIARY_PAYER_ID >0 AND C.HIDEN=0 THEN SUM(L.AMOUNT) ELSE 0 END AS TER_INS_AGING,
CASE WHEN L.RESP_PARTY =4 THEN SUM(L.AMOUNT) ELSE 0 END AS PAT_AGING
FROM VISIT_PROCEDURE VP
JOIN CLAIM C
ON (C.CLAIM_ID = VP.CLAIM_ID AND C.CLINIC_ID = VP.CLINIC_ID)
JOIN LEDGER L
ON (L.CLAIM_ID = L.CLAIM_ID AND VP.CLINIC_ID = L.CLINIC_ID)
WHERE C.CLINIC_ID = 34847 AND L.TYPE IN(1,8,9,10,11) AND L.ACTIVE=1
GROUP BY VP.PROCEDURE_ID,L.TYPE,L.RESP_PARTY,L.ACTIVE)T1
Thanks
Sunil

without extra dissecting your SQL, look into your join on LEDGER... you have it doing the CLAIM_ID on the same value...
JOIN LEDGER L ON L.CLAIM_ID = L.CLAIM_ID AND VP.CLINIC_ID = L.CLINIC_ID
Should the "L.Claim_ID" be joined to a "VP.Claim_ID"??? or something else?
Ok, so with a little bit of time, I came up with this... I would swap the query around some. In addition, make sure you have an index ON your CLAIM table on Clinic_ID AND Hiden. Also, your inner query is breaking down the SUM of distinct parts of insurance claims, yet you are not doing anything ELSE with them except summing them in the outer. I would change to just sum ONCE at the outer for the given conditions
SELECT STRAIGHT_JOIN
SUM( IF( L.RESP_PARTY = 1
AND VP.STATUS IN(3,5)
AND VP.PRIMARY_PAID = 0
AND VP.PRIMARY_PENDING > 0
AND C.PRIMARY_PAYER_ID > 0, L.AMOUNT, 0 )
+
IF( L.RESP_PARTY = 2
AND VP.STATUS IN(6,7,5)
AND VP.SECONDARY_PAID = 0
AND VP.SECONDARY_PENDING > 0
AND VP.PRIMARY_PENDING <= 0
AND C.SECONDARY_PAYER_ID > 0, L.AMOUNT, 0 )
+
IF( L.RESP_PARTY = 3
AND VP.STATUS IN(8,9,5)
AND VP.TERTIARY_PAID = 0
AND VP.TERTIARY_PENDING > 0
AND VP.PRIMARY_PENDING <= 0
AND VP.SECONDARY_PENDING <= 0
AND C.TERTIARY_PAYER_ID > 0, L.AMOUNT, 0 ) ) as INS_AGING,
SUM( IF( L.RESP_PARTY = 4, L.AMOUNT, 0 )) as PAT_AGING
FROM
CLAIM C
JOIN VISIT_PROCEDURE VP
ON C.CLAIM_ID = VP.CLAIM_ID
AND C.CLINIC_ID = VP.CLINIC_ID
JOIN LEDGER L
ON VP.CLINIC_ID = L.CLINIC_ID
AND VP.CLAIM_ID = L.CLAIM_ID
AND L.TYPE IN ( 1, 8, 9, 10, 11 )
AND L.ACTIVE = 1
WHERE
C.CLINIC_ID = 34847
AND C.HIDEN = 0

If you're looking to get the SUM() of your data, I don't see you getting it any other way. That said, this is pretty complex and you might benefit from breaking it down into a stored proc and splitting the calculations up into stages.
Btw what does slow mean here? 1 second rather than 0.001? Or, 2 minutes?

Related

Integrate calculated AVG into same query

I have some troubles and hope you will help me. I need to calculate how many contracts there are in which hcb.sum:
<= 10k
greater than 10k but < AVG
greater than AVG
In the first case, everything is simple, but the problem arises when I need to count the following two cases: "> 10 but < AVG" and "> AVG". I can't solve this problem. How to integrate the calculated AVG into this query. Hope you understand what i need. Perhaps you can help me. Thanks in advance. Select is below:
SELECT hcb.id AS 'ID'
,hcb.name AS 'Name'
,SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ <= 10000 THEN 1 ELSE 0 END) AS '<= 10k'
,SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ BETWEEN 10000.01 AND **AVG** THEN 1 ELSE 0 END) AS '> 10k < AVG'
,SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ > **AVG** THEN 1 ELSE 0 END) AS '> AVG'
,AVG(hcb.summ) AS 'AVG summ'
FROM DBO AS hcb
WHERE hcb.stat IN (15, 20)
AND hcb.optstat <> 2999
AND hcb.opt = 'CI'
GROUP BY hcb.id, hcb.name
Use window functions. Presumably, you want the average with the where conditions, so:
SELECT hcb.id AS id,
hcb.name AS Name,
SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ <= 10000
THEN 1 ELSE 0
END) AS "<= 10k",
SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ > 10000 AND hcb.summ <= hcb.avg_summ
THEN 1 ELSE 0
END) AS "> 10k < AVG",
SUM(CASE WHEN hcb.kind = 'NEW' AND hcb.opt = 'CI' AND hcb.summ > hcb.avg_summ
THEN 1 ELSE 0
END) AS "> AVG",
avg_summ
FROM (SELECT hcb.*,
AVG(summ) OVER () as avg_summ
FROM DBO AS hcb
WHERE hcb.stat IN (15, 20) AND
hcb.optstat <> 2999 AND
hcb.opt = 'CI'
) hcb
GROUP BY hcb.id, hcb.name, avg_summ;
Note other changes to the query:
The column aliases are defined using double quotes not single quotes. Only use single quotes for string and date constants -- otherwise, you will one day have a confusion where you refer to a column using single quotes.
The second between is removed, replaced with >, so values between 10000 and 10000.01 are included.
If you want the overall average not subject to the filtering conditions, then move the WHERE conditions to the outer query.
I have used 3 different joins and then in SELECT statement brought up 3 different values trough something like COALESCE(MAX(d.[<10k]),0) AS '<10k'
LEFT JOIN (
SELECT r.id AS 'ID'
,COUNT(r.name) AS '<10k'
FROM DBO as r
WHERE r.stat IN (15, 20)
AND r.optstat <> 2999
AND r.opt = 'CI'
AND r.kind = 'NEW'
AND r.summ BETWEEN 10000 AND (SELECT AVG(ci.summ)
FROM DBO as ci
WHERE ci.stat IN (15, 20)
AND ci.optstat <> 2999
AND ci.opt = 'CI'
AND ci.kind = 'NEW')
GROUP BY r.id) AS d ON a.id = d.ID
Maybe it's not a best way to solve a problem, but it works for me. Thax a lot for some suggestions, they helped me. Cheers!

Return 1 or 0 in SQL depending on the multiple statements

If I find that some of the user exists with such a parameters, I want to get 1 otherwise 0. In the future I'll have to add more blocks. But it doesn't seem to work now. What am I doing wrong?
SELECT CAST(CASE WHEN EXISTS(SELECT 1
FROM Customers
WHERE Country = 'France' AND PostalCode%2 = 0)
OR (WHERE Country = 'Germany' AND PostalCode%2 = 0))
)
THEN 1
ELSE 0
END AS BIT)
You need two separate exists:
SELECT CAST(CASE WHEN EXISTS (SELECT 1
FROM Customers
WHERE Country = 'France' AND PostalCode%2 = 0
)
THEN 1
WHEN EXISTS (SELECT 1
FROM Customers
WHERE Country = 'Germany' AND PostalCode%2 = 0
)
THEN 1
ELSE 0
END AS BIT)
Actually, I broke this into two separate THEN clauses. This is almost equivalent to using OR, but because the logic is inside a CASE, THEN seems more natural. (The difference is that the optimizer could choose to re-arrange the OR conditions, but the THEN conditions are executed in lexical order.)
If your statements are actually this simple, you can combine them as:
SELECT CAST(CASE WHEN EXISTS (SELECT 1
FROM Customers
WHERE Country IN ('France', 'Germany') AND PostalCode%2 = 0
)
THEN 1
ELSE 0
END AS BIT)
It looks to me like you're just having issues with your bracketing:
SELECT CAST(
CASE WHEN EXISTS(
SELECT 1
FROM Customers
WHERE (Country = 'France' AND PostalCode%2 = 0)
OR (Country = 'Germany' AND PostalCode%2 = 0)
) THEN 1 ELSE 0 END AS BIT)
Building on Gordon's assumption that PostalCode%2 = 0 for all tested 'sets' of conditionals (you haven't said as much yet), you could likewise shorten this to:
SELECT CAST(
CASE WHEN EXISTS(
SELECT 1
FROM Customers
WHERE PostalCode%2 = 0
AND Country IN ('France', 'Germany')
) THEN 1 ELSE 0 END AS BIT)

[HY000][1111] Invalid use of group function

I have searched a lot ,but none of other questions with error 1111 solves my problem.
My needs are to count the distinct phone number of some id
The following code works:
SELECT
a.id_borrow_application,
count(DISTINCT c.phone_no) CVG_CALL_OUT_COUNTS_6M
FROM t_snow_borrow_application_id a
JOIN t_snow_call_mobile b
JOIN t_snow_call_record_201612 c ON
(
a.id_borrow_application = b.id_borrow_application
AND b.id = c.id_call_mobile
)
WHERE c.call_type = 0
GROUP BY a.id_borrow_application;
But when I want to write 4 similar queries together,the error in title
happens.
[HY000][1111] Invalid use of group function
SELECT
a.id_borrow_application,
sum(CASE WHEN call_type = 0
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_OUT_COUNTS_6M,
sum(CASE WHEN call_type = 0 AND c.days <= 30
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_OUT_COUNTS_1M,
sum(CASE WHEN call_type = 1
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_IN_COUNTS_6M,
sum(CASE WHEN call_type = 1 AND c.days <= 30
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_IN_COUNTS_1M
FROM t_snow_borrow_application_id a
JOIN t_snow_call_mobile b
JOIN t_snow_call_record_201612 c ON
(
a.id_borrow_application = b.id_borrow_application
AND b.id = c.id_call_mobile
)
GROUP BY a.id_borrow_application;
Do I have to write 4 queries?
You are nesting aggregate function which is not allowed in MySQL.
You don't actually need the sum function for count distinct phone_nos for different conditions. Take the count (distinct outside the case and remove sum function and else clause of the case.
Try this:
select a.id_borrow_application,
count(distinct case when call_type = 0 then c.phone_no end) CVG_CALL_OUT_COUNTS_6M,
count(distinct case when call_type = 0
and c.days <= 30 then c.phone_no end) CVG_CALL_OUT_COUNTS_1M,
count(distinct case when call_type = 1 then c.phone_no end) CVG_CALL_IN_COUNTS_6M,
count(distinct case when call_type = 1
and c.days <= 30 then c.phone_no end) CVG_CALL_IN_COUNTS_1M
from t_snow_borrow_application_id a
join t_snow_call_mobile b
join t_snow_call_record_201612 c on (
a.id_borrow_application = b.id_borrow_application
and b.id = c.id_call_mobile
)
group by a.id_borrow_application;

how to get SUM() of COUNT() column in MySQL

i have the following query, tried using case statement
SELECT t.inst_id, t.inst_username, tcm.city_name,
SUM(CASE WHEN psb.pms_student_bucket_id IS NULL THEN 1 ELSE 0 END) AS not_assiged,
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) BETWEEN 1 AND 50 THEN 1 ELSE 0 END) AS '1-50',
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) > 50 THEN 1 ELSE 0 END) AS ' > 50'
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id;
I need SUM of pms_student_bucket_id column when their COUNT is '1-50' and '>50'. Right now this query is saying Invalid use of group function.
How would I SUM on COUNT of "pms_student_bucket_id" equals/between some value in mysql?
you could put it in a subquery
SELECT inst_id, inst_username, city_name,
SUM(pms_student_bucket_id IS NULL ) AS not_assiged,
SUM(num_bucket >=10 AND num_bucket <= 20) AS '10 - 20'
SUM(num_bucket <= 50) AS '1-50',
SUM(num_bucket > 50) AS ' > 50'
FROM
( SELECT t.inst_id, t.inst_username, tcm.city_name,psb.pms_student_bucket_id,
COUNT(psb.pms_student_bucket_id) as num_bucket
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id
)t1
GROUP BY inst_id;
note you can use the boolean values returned to do what you want.. aka you don't need a case statement, the boolean value returns a 1 or 0 which can then be summed..

selecting total comments (pos & neg) + latest comment for each

I am writing a query to get the top 10 rated businesses, the number of positive comments for each business, the number of negative comments for each business and the latest comment for each of these businesses.
SELECT comment.bis_id, Sum( Case When comment.rating <= 2 Then 1 Else 0 End ) As NegVotes
, Sum( Case When comment.rating >= 4 Then 1 Else 0 End ) As PosVotes, bis.bis_name
FROM bis, comment
WHERE comment.bis_id = bis.bis_id
GROUP BY bis_id
ORDER BY PosVotes DESC
LIMIT 0, 10";
The above gets positive comments and negative comments, but I can't seem to work out how to get the latest comment as well.
SELECT
c.bis_id
, Sum( Case When c.rating <= 2 Then 1 Else 0 End ) As NegVotes
, Sum( Case When c.rating >= 4 Then 1 Else 0 End ) As PosVotes
, b.bis_name
, cc.last_comment
FROM bis b
INNER JOIN comment c on (c.bis_id = b.bis_id)
INNER JOIN (SELECT c2.bis_id, c2.comment_text as last_comment
FROM comment c2
GROUP BY c2.bis_id
HAVING c2.comment_date = MAX(c2.comment_date) ) cc
ON (cc.bis_id = b.bis_id)
GROUP BY b.bis_id
ORDER BY PosVotes DESC
LIMIT 10 OFFSET 0