MySQL grouping giving 4 rows instead of 1 - mysql

I'm having a hard time getting the rows to group like needed. It gives me 4 rows instead of 1. I'm sure it's something simple, but I can't figure it out.
SELECT DISTINCT
th.name Serial,
CASE WHEN td.parameter = 4854455 THEN TRIM(LEADING '0' FROM td.text) ELSE NULL END Auto_PF,
CASE WHEN td.parameter = 797902 THEN TRIM(LEADING '0' FROM td.text) ELSE NULL END Auto_IC,
CASE WHEN td.parameter = 797402 THEN TRIM(LEADING '0' FROM td.text) ELSE NULL END Auto_NIC,
CASE WHEN td.parameter = 4854430 THEN TRIM(LEADING '0' FROM td.text) ELSE NULL END Auto_E46
FROM thisdata td
INNER JOIN this th
ON td.thisid = th.id
WHERE td.parameter IN ('4854455', '797902', '797402', '4854430', '6332168',
'6332160', '798102', '12000003', '12020956', '12020947', '12015253')
AND td.created >= (NOW() - INTERVAL 1 MONTH)
GROUP BY Serial, td.parameter, td.text
...
Result1

I think you should be aggregating only by the name, and then pivoting the CASE expressions:
SELECT
th.name Serial,
MAX(CASE WHEN td.parameter = 4854455 THEN TRIM(LEADING '0' FROM td.text) END) Auto_PF,
MAX(CASE WHEN td.parameter = 797902 THEN TRIM(LEADING '0' FROM td.text) END) Auto_IC,
MAX(CASE WHEN td.parameter = 797402 THEN TRIM(LEADING '0' FROM td.text) END) Auto_NIC,
MAX(CASE WHEN td.parameter = 4854430 THEN TRIM(LEADING '0' FROM td.text) END) Auto_E46
FROM thisdata td
INNER JOIN this th
ON td.thisid = th.id
WHERE
td.parameter IN ('4854455', '797902', '797402', '4854430', '6332168', '6332160',
'798102', '12000003', '12020956', '12020947', '12015253') AND
td.created >= (NOW() - INTERVAL 1 MONTH)
GROUP BY
th.name;

Related

Grouping different column into one row

How to make one row in different rows and column
SELECT
internal_id, store_id, user_id, shift_info,
DATE(log_datetime) dates,
(case when log_action = '0' then TIME(log_datetime) end) as time_in,
(case when log_action = '0' then CONCAT(log_lat, ",", log_lng) end) as loc_in,
(case when log_action = '1' then TIME(log_datetime) end) as time_out,
(case when log_action = '1' then CONCAT(log_lat, ",", log_lng) end) as loc_out
FROM
attendance_store_user
WHERE
user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"
i want result like this :
You could try using a join of the same table filter for null time_out and time_in
select a.dates, a.store_id, a,time_in, b.time_out
FROM attendance_store_user a
INNER JOIN attendance_store_user b on a.dates = b.dates
and a.user_id = b.user_id
and a.time_out is null
and b.time_in is null
WHERE a.user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"

SQL Query: Adding Percentage

I have a query that works but in addition to what I already have I want to add one extra column for each category free,reduced,paid and certified free with the percentage compared to the total number of students. Can anyone help me?
select
count(case when Lunchstatus = 'P' then 1 else null end) as Paid
, count(case when LunchStatus = 'R' then 1 else null end) as Reduced
, count(case when LunchStatus = 'F' then 1 else null end) as Free
, count(case when LunchStatus = 'fdc' then 1 else null end) as CertifiedFree
, count(case when LunchStatus = 'P' then 1
when LunchStatus = 'fdc' then 1
when LunchStatus = 'R' then 1
when LunchStatus = 'F' then 1
else null
end) as Total
from students
where enroll_status = 0
and schoolid = %param1%
Treat you existing query as a derived table, cross join for the total count, then calculate your percentages:
select
d.*
, d.Paid * 100.0 / cj.totcount as paid_pct
... more like that
from (
select
count(case when Lunchstatus = 'P' then 1 else null end) as Paid
, count(case when LunchStatus = 'R' then 1 else null end) as Reduced
, count(case when LunchStatus = 'F' then 1 else null end) as Free
, count(case when LunchStatus = 'fdc' then 1 else null end) as CertifiedFree
, count(case when LunchStatus = 'P' then 1
when LunchStatus = 'fdc' then 1
when LunchStatus = 'R' then 1
when LunchStatus = 'F' then 1
else null
end) as Total
from students
where enroll_status = 0
and schoolid = %param1%
) d
CROSS JOIN (
select count(*) as totcount
from students
where enroll_status = 0
and schoolid = %param1%
) cj

Mysql query optimization takes more than 30 sec

Hi friends can any one please help me to optimize this query ,it takes more than 30 sec.
any suggestion is warmly welcome.
Query :
SELECT
CONCAT(CCD.CONTACT_FIRST_NAME, ' ', CCD.CONTACT_LAST_NAME) AS NAME,
A.EMAIL_IDS,
CCD.UNSUBSCRIBE,
IFNULL(CSL.LOG_DATE, '') AS LOG_DATE,
CSL.IP_ADDRESS,
IF(CSL.BROWSER IS NULL, '', CSL.BROWSER) AS BROWSER,
(CASE
WHEN (UNSUBSCRIBE = 0 OR UNSUBSCRIBE IS NULL) THEN 'Opted In'
ELSE (CASE
WHEN (UNSUBSCRIBE = 1) THEN 'Opted Out'
ELSE (CASE
WHEN
((UNSUBSCRIBE = 2 OR UNSUBSCRIBE = 3)
AND CCD.CONTACT_ID NOT IN (SELECT
CONTACT_ID
FROM
CM_SUBSCRIPTION_MAIL_DATA
WHERE
IS_MAIL_SENT = 'Y'))
THEN
'Opt-In Request not Sent'
ELSE 'Opt-In Pending'
END)
END)
END) AS CURR_SUB,
(CASE
WHEN (SUBSCRIBE_FROM = 0) THEN 'Opted In'
ELSE (CASE
WHEN (SUBSCRIBE_FROM = 1) THEN 'Opted Out'
ELSE (CASE
WHEN (SUBSCRIBE_FROM = 2 OR SUBSCRIBE_FROM = 3) THEN 'Opt-In Pending'
ELSE ''
END)
END)
END) AS SUB_FROM,
SUBSCRIBE_FROM,
(CASE
WHEN (SUBSCRIBE_TO = 0) THEN 'Opted In'
ELSE (CASE
WHEN (SUBSCRIBE_TO = 1) THEN 'Opted Out'
ELSE (CASE
WHEN (SUBSCRIBE_TO = 2 OR SUBSCRIBE_TO = 3) THEN 'Opt-In Pending'
ELSE ''
END)
END)
END) AS SUB_TO,
SUBSCRIBE_TO
FROM
CM_CONTACT_DETAILS CCD
LEFT JOIN
ADDRESS A ON CCD.CONTACT_ID = A.FOREIGN_ID
LEFT JOIN
CM_SUBSCRIPTION_LOGS CSL ON CSL.CONTACT_ID = CCD.CONTACT_ID
WHERE
1 = 1
GROUP BY CSL.LOG_DATE , CCD.CONTACT_ID
ORDER BY NAME DESC , LOG_DATE DESC
LIMIT 0 , 20
Your case/when can be simplified, but I believe the killer of your query was the correlated NOT IN SELECT clause for your Opt-in request not sent.
I've change your query to do a left-join to your mailing table based on the contact AND the mailed status of "Y". So this simplifies your case to only have to check for IS NULL of the mailing table contact ID.
You can't do too much on performance since your Group by is by columns from different tables that won't take advantage of any index optimization, then all that ordered by the name makes it more of an issue... but the correlated subquery per the field being executed every time to a left-join SHOULD help.
SELECT
CONCAT(CCD.CONTACT_FIRST_NAME, ' ', CCD.CONTACT_LAST_NAME) AS NAME,
A.EMAIL_IDS,
CCD.UNSUBSCRIBE,
IFNULL(CSL.LOG_DATE, '') AS LOG_DATE,
CSL.IP_ADDRESS,
IF(CSL.BROWSER IS NULL, '', CSL.BROWSER) AS BROWSER,
CASE WHEN UNSUBSCRIBE = 0 OR UNSUBSCRIBE IS NULL THEN 'Opted In'
WHEN UNSUBSCRIBE = 1 THEN 'Opted Out'
WHEN UNSUBSCRIBE IN (2,3) AND SMD.CONTACT_ID IS NULL THEN 'Opt-In Request not Sent'
ELSE 'Opt-In Pending' END AS CURR_SUB,
CASE WHEN SUBSCRIBE_FROM = 0 THEN 'Opted In'
WHEN SUBSCRIBE_FROM = 1 THEN 'Opted Out'
WHEN SUBSCRIBE_FROM = 2 OR SUBSCRIBE_FROM = 3 THEN 'Opt-In Pending'
ELSE '' END AS SUB_FROM,
SUBSCRIBE_FROM,
CASE WHEN SUBSCRIBE_TO = 0 THEN 'Opted In'
WHEN SUBSCRIBE_TO = 1 THEN 'Opted Out'
WHEN SUBSCRIBE_TO = 2 OR SUBSCRIBE_TO = 3 THEN 'Opt-In Pending'
ELSE '' END AS SUB_TO,
SUBSCRIBE_TO
FROM
CM_CONTACT_DETAILS CCD
LEFT JOIN ADDRESS A
ON CCD.CONTACT_ID = A.FOREIGN_ID
LEFT JOIN CM_SUBSCRIPTION_LOGS CSL
ON CSL.CONTACT_ID = CCD.CONTACT_ID
LEFT JOIN CM_SUBSCRIPTION_MAIL_DATA SMD
ON CCD.CONTACT_ID = SMD.CONTACT_ID
AND IS_MAIL_SENT = 'Y'
WHERE
1 = 1
GROUP BY
CSL.LOG_DATE,
CCD.CONTACT_ID
ORDER BY
NAME DESC,
LOG_DATE DESC
LIMIT
0, 20

Case When with AND?

I want to use Case When with AND condition and it is not calculating the sum properly.
For example:
SELECT DATE(`SubmitDate`),
SUM(CASE status WHEN 'New' AND `Type` = 'consumer' THEN 1 ELSE 0 END) as new_consumer,
SUM(CASE status WHEN 'New' AND `Type` = 'business' THEN 1 ELSE 0 END) as new_business
FROM report
WHERE `source` = 'net'
group by DATE(`SubmitDate`) Order by `SubmitDate` DESC
You need to use CASE WHEN [Condition] THEN... rather than a simple case expression:
SELECT DATE(`SubmitDate`),
SUM(CASE WHEN status = 'New' AND `Type` = 'consumer' THEN 1 ELSE 0 END) as new_consumer,
SUM(CASE WHEN status = 'New' AND `Type` = 'business' THEN 1 ELSE 0 END) as new_business
FROM report
WHERE `source` = 'net'
group by DATE(`SubmitDate`) Order by `SubmitDate` DESC
You should write
CASE WHEN status='New' AND `Type` = 'consumer' THEN 1 ELSE 0 END
Check the syntax of CASE WHEN

Getting total value from each field?

How do I get the Total value of Yes, No, Other fields of each username?
I like to add Total field.
SELECT Username,
SUM(CASE WHEN type = 'Yes' THEN 1 ELSE NULL END) as Yes,
SUM(CASE WHEN type = 'No' THEN 1 ELSE NULL END) as No,
SUM(CASE WHEN type = '' THEN 1 ELSE NULL END) as Other
//How to get total of Yes/No/Other
FROM table
WHERE source = 'CompanyName' ";
Also the highest Total goes at the top order.
use 0 instead of NULL, add the missing group by and use COUNT(*) to get the total of each group and order the result:
SELECT Username,
SUM(CASE WHEN type = 'Yes' THEN 1 ELSE 0 END) as Yes,
SUM(CASE WHEN type = 'No' THEN 1 ELSE 0 END) as No,
SUM(CASE WHEN type = '' THEN 1 ELSE 0 END) as Other,
COUNT(*) as TOTAL
FROM table
WHERE source = 'CompanyName'
group by Username
order by TOTAL desc;
This assumes that type can only be 'Yes', 'No' or ''.
Use a sub query to sum up your results and add a sort:
select yes, no, other, yes + no + other as Total
from (
SELECT Username,
SUM(CASE WHEN type = 'Yes' THEN 1 ELSE 0 END) as Yes,
SUM(CASE WHEN type = 'No' THEN 1 ELSE 0 END) as No,
SUM(CASE WHEN type = '' THEN 1 ELSE 0 END) as Other
FROM table
WHERE source = 'CompanyName'
)
order by (yes + no + other) desc
Don't use SUM(null), the SUM of (1,1,1,null) = null, not 3.
SELECT s.*, s.yes+s.no+s.other as all FROM (
SELECT Username,
SUM(CASE WHEN type = 'Yes' THEN 1 ELSE 0 END) as Yes,
SUM(CASE WHEN type = 'No' THEN 1 ELSE 0 END) as No,
SUM(CASE WHEN type = '' THEN 1 ELSE 0 END) as Other
FROM table
WHERE source = 'CompanyName'
GROUP BY Username
) s
ORDER BY all DESC