Select with case when + join, MYSQL - mysql

Guys are you able to help me in this below case?
I'm wanna to select and change the results:
My code looks as follow:
$USER_STORY = $this->lang->line('application_status_change_user_story');
$TO_DO = $this->lang->line('application_status_change_to_do');
$IN_PROGRESS = $this->lang->line('application_status_change_in_progress');
$DONE = $this->lang->line('application_status_change_done');
$UNDONE = $this->lang->line('application_status_change_undone');
SELECT sum(project_has_tasks.estimated_hours) as val, project_has_tasks.name,
project_has_tasks.start_date,
project_has_tasks.due_date,
project_has_tasks.progress,
TIME_FORMAT(SEC_TO_TIME(sum(project_has_tasks.time_spent)),'%k.%i')
as total_time, users.id, users.firstname, users.lastname,(case
when 'user_story' then '$USER_STORY'
when 'to_do' then '$TO_DO'
when 'in_progress' then '$IN_PROGRESS'
when 'done' then '$DONE'
when 'undone' then '$UNDONE'
else 'NOTHING'
end) as status
FROM project_has_tasks
RIGHT JOIN users ON project_has_tasks.user_id
= users.id WHERE project_has_tasks.project_id ='99'
GROUP BY project_has_tasks.id ASC
What to modify to get a proper results? Now I'm getting NOTHING in status column, but no errors.

I think your case statement is wrong, There no condition is checking so only it return the last else statement
SELECT sum(project_has_tasks.estimated_hours) as val, project_has_tasks.name,
project_has_tasks.start_date,
project_has_tasks.due_date,
project_has_tasks.progress,
TIME_FORMAT(SEC_TO_TIME(sum(project_has_tasks.time_spent)),'%k.%i')
as total_time, users.id, users.firstname, users.lastname,(case
when project_has_tasks.status = 'user_story' then '$USER_STORY'
when project_has_tasks.status = 'to_do' then '$TO_DO'
when project_has_tasks.status = 'in_progress' then '$IN_PROGRESS'
when project_has_tasks.status = 'done' then '$DONE'
when project_has_tasks.status = 'undone' then '$UNDONE'
else 'NOTHING'
end) as status
FROM project_has_tasks
RIGHT JOIN users ON project_has_tasks.user_id
= users.id WHERE project_has_tasks.project_id ='99'
GROUP BY project_has_tasks.id ASC

Related

Hello Can any one Help me to write this Query in Joins instead of Sub query?

SELECT ST.Id,
ST.Label,
ST.Asset,
CASE
WHEN ST.RFID = '' THEN 'NULL'
ELSE ST.RFID
END AS RFID,
CASE
WHEN ST.Type = 'O' THEN 'Odometer'
ELSE 'Engine Hours'
END AS AccumulatorType,
ST.AppId,
ST.Timestamp,
ST.Accumulator,
CASE
WHEN ST.Flag = 0 THEN 'Disabled'
WHEN ST.Flag = 1 THEN 'Active'
WHEN ST.Flag = 3 THEN 'Rented'
WHEN ST.Flag = 4 THEN 'Bypass'
WHEN ST.Flag = 5 THEN 'Tanker'
END AS TYPE,
(SELECT COUNT(*)
FROM sync
WHERE RowId = ST.Id
AND DefinitionId = 1
AND Status = 1) AS Updated,
(SELECT COUNT(*)
FROM sync
WHERE RowId = ST.Id
AND DefinitionId = 1
AND Status = 0) AS Remaining
FROM SecondaryTags AS ST
WHERE AppId = #AppId
Why do you want to rewrite the logic? Because you have filtering in the outer query, the subquery is likely to be the most performant method for the calculation.
You can speed the subquery by being sure that you have the write indexes. In this case, you want an index on sync(RowId, DefinitionId, StatusId):
create index idx_sync_rowid_definitionid_statusid
on sync(RowId, DefinitionId, StatusId)
You can rewrite the query as:
select . . .,
s.updated, s.remaining
from SecondaryTags st join
(select rowid, sum(status = 1) as updated, sum(status = 0) as remaining
from sync s
where s.definitionId = 1
group by s.rowid
) s
on s.rowid = st.id
where st.AppId = #AppId;
From a performance perspective, though, I think the index is a better idea.
select st.*
, s.updated
, s.remaining
from SecondaryTags st
join (select rowid
, sum(status = 1) as updated
, sum(status = 0) as remaining
from sync s
where s.definitionId = 1
group
by s.rowid
) s
on s.rowid = st.id
where st.AppId = 2;

MySQL query taking too much time

query taking 1 minute to fetch results
SELECT
`jp`.`id`,
`jp`.`title` AS game_title,
`jp`.`game_type`,
`jp`.`state_abb` AS game_state,
`jp`.`location` AS game_city,
`jp`.`zipcode` AS game_zipcode,
`jp`.`modified_on`,
`jp`.`posted_on`,
`jp`.`game_referal_amount`,
`jp`.`games_referal_amount_type`,
`jp`.`status`,
`jp`.`is_flaged`,
`u`.`id` AS employer_id,
`u`.`email` AS employer_email,
`u`.`name` AS employer_name,
`jf`.`name` AS game_function,
`jp`.`game_freeze_status`,
`jp`.`game_statistics`,
`jp`.`ats_value`,
`jp`.`integration_id`,
`u`.`account_manager_id`,
`jp`.`model_game`,
`jp`.`group_id`,
(CASE
WHEN jp.group_id != '0' THEN gm.group_name
ELSE 'NA'
END) AS group_name,
`jp`.`priority_game`,
(CASE
WHEN jp.country != 'US' THEN jp.country_name
ELSE ''
END) AS game_country,
IFNULL((CASE
WHEN
`jp`.`account_manager_id` IS NULL
OR `jp`.`account_manager_id` = 0
THEN
(SELECT
(CASE
WHEN
account_manager_id IS NULL
OR account_manager_id = 0
THEN
`u`.`account_manager_id`
ELSE account_manager_id
END) AS account_manager_id
FROM
user_user
WHERE
id = (SELECT
user_id
FROM
game_user_assigned
WHERE
game_id = `jp`.`id`
LIMIT 1))
ELSE `jp`.`account_manager_id`
END),
`u`.`account_manager_id`) AS acc,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '1'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS somewhatgame,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '2'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS verygamecommitted,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '3'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS notgame,
(SELECT
COUNT(joa.id) AS applicationcount
FROM
game_refer_to_member jrmm
INNER JOIN
game_refer jrr ON jrr.id = jrmm.rid
INNER JOIN
game_applied joa ON jrmm.id = joa.referred_by
WHERE
jrmm.STATUS = '1'
AND jrr.referby_user_id IN (SELECT
ab_testing_user_id
FROM
ab_testing)
AND joa.game_post_id = rpr.recach_limit_game_id
AND (rpr.recach_limit = 1
OR rpr.recach_limit = 2)) AS gamecount
FROM
(`game_post` AS jp)
JOIN
`user_info` AS u ON `jp`.`user_user_id` = `u`.`id`
JOIN
`game_functional` jf ON `jp`.`game_functional_id` = `jf`.`id`
LEFT JOIN
`group_musesm` gm ON `gm`.`group_id` = `jp`.`group_id`
LEFT JOIN
`recach_limit` rpr ON `jp`.`id` = `rpr`.`recach_limit_game_id`
WHERE
`jp`.`status` != '3'
GROUP BY `jp`.`id`
ORDER BY `posted_on` DESC
LIMIT 10
I would first suggest not nesting select statements because this will cause an n^x performance hit on every xth level and I see at least 3 levels of selects inside this query.
Add index
INDEX(status, posted_on)
Move LIMIT inside
Then, instead of saying
FROM (`game_post` AS jp)
say
FROM ( SELECT id FROM game_post
WHERE status != 3
ORDER BY posted_on DESC
LIMIT 10 ) AS ids
JOIN game_post AS jp USING(id)
(I am assuming that the PK of jp is (id)?)
That should efficiently use the new index to get the 10 ids needed. Then it will reach back into game_post to get the other columns.
LEFT
Also, don't say LEFT unless you need it. It costs something to generate NULLs that you may not be needing.
Is GROUP BY necessary?
If you remove the GROUP BY, does it show dup ids? The above changes may have eliminated the need.
IN(SELECT) may optimize poorly
Change
AND jrr.referby_user_id IN ( SELECT ab_testing_user_id
FROM ab_testing )
to
AND EXISTS ( SELECT * FROM ab_testing
WHERE ab_testing_user_id = jrr.referby_user_id )
(This change may or may not help, depending on the version you are running.)
More
Please provide EXPLAIN SELECT if you need further assistance.

MySQL multiple tables conditional filter

I want to check the validity of a user_id, from a table of users that contains three types of users (type i, c and p).
For users of type c to be valid, the current user.party_id has to be present in the customer_partner table against the supplied $PNR.
For users of type i to be valid, the current user.party_id has top be present in the installer_partner table against the supplied $PNR.
For users of type p to be valid, the current user.party_id has to be the supplied $PNR.
I want the returned row to be the user details if valid, or no rows if invalid. I have tried a couple of ways to do this, but unsuccessfully.
EXAMPLE 1: I am using a CASE in the select then placing a v or e value in the resulting column, then filtering out in the WHERE statement, but this gives me Unknown column 'valid_user' in 'where clause' error.
SELECT
CASE users.party_type
WHEN 'c'
THEN IF(users.party_id IN (SELECT pnrcus.customer_id
FROM customer_partner AS pnrcus
WHERE pnrcus.partner_id = '.$PNR.'),'v','e')
WHEN 'i'
THEN IF(users.party_id IN (SELECT pnrins.installer_id
FROM installer_partner AS pnrins
WHERE pnrins.partner_id = '.$PNR.'),'v','e')
WHEN 'p'
THEN IF(users.party_id = '.$PNR.','v','e')
ELSE 'e'
END AS valid_user,
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND valid_user = 'v'
AND users.account_status = 'a'
EXAMPLE 2: I am using OR statements in the WHERE part of the sql. This returns the wrong rows.
SELECT
users.party_type
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
AND (
parties.party_type = 'c'
AND users.party_id IN (SELECT pnrcus.customer_id
FROM sma_customer_partner AS pnrcus
WHERE pnrcus.partner_id = .$PNR.')
) OR (
parties.party_type = 'i'
AND users.party_id IN (SELECT pnrins.installer_id
FROM sma_installer_partner AS pnrins
WHERE pnrins.partner_id = .$PNR.')
) OR (
parties.party_type = 'p'
AND users.party_id = '.$PNR.'
)
A quick fix to your problem is to add a HAVING clause for the column in the resultset you created:
SELECT
CASE users.party_type
WHEN 'c'
THEN IF(users.party_id IN (SELECT pnrcus.customer_id
FROM customer_partner AS pnrcus
WHERE pnrcus.partner_id = '.$PNR.'),'v','e')
WHEN 'i'
THEN IF(users.party_id IN (SELECT pnrins.installer_id
FROM installer_partner AS pnrins
WHERE pnrins.partner_id = '.$PNR.'),'v','e')
WHEN 'p'
THEN IF(parties.party_id = '.$PNR.','v','e')
ELSE 'e'
END AS valid_user,
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
WHERE LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
HAVING valid_user = 'v'
But, frankly, I'd do this:
SELECT
users.party_type
users.email_user_id,
users.party_id,
users.person_id,
users.first_name,
users.last_name
FROM users AS users
LEFT JOIN customer_partner AS pnrcus
ON pnrcus.partner_id = '.$PNR.'
AND pnrcus.customer_id = users.party_id
AND users.party_type = 'c'
LEFT JOIN installer_partner AS pnrins
ON pnrins.partner_id = '.$PNR.'
AND pnrins.installer_id = users.party_id
AND pnrins.party_type = 'i'
WHERE
LCASE(users.email_user_id) = LCASE('.$UID.')
AND users.password = '.$PWD.'
AND users.account_status = 'a'
AND (
( users.party_type ='p' AND users,party_id = '.$PNR.' )
OR pnrcus.partner_id IS NOT NULL
OR pnrins.partner_id IS NOT NULL
)
GROUP BY users.email_user_id;
Note BTW that this is very slow:
LCASE(users.email_user_id) = LCASE('.$UID.')
You might want to use a collation where 'A'='a' == true (all _ci ones are), or store it lowercase, and provide it lowercase. As it stands it cannot use an index.

Count, SUM, LEFT JOIN and GROUP BY in query not working right

I have tried a few things but I can't seem to figure out what's causing the problem.
When I remove the totalHours part, the query works fine. But with it, it displays the right number of hours but the wrong number of Jobs, Selected and Winners.
Could someone please tell me what I am doing wrong?
Thanks in advance.
Here is my query;
SELECT
crmCandidate.candidateID,
crmCandidate.candidateName,
COUNT(DISTINCT crmJoin.joinID) AS Jobs,
SUM(IF(crmJoin.joinExtra = 'select', 1, 0)) AS Selected,
SUM(IF(crmJoin.joinExtra = 'winner', 1, 0)) AS Winner,
ROUND(SUM(crmDays.total)) AS totalDays
FROM crmCandidate
LEFT JOIN crmJoin ON (crmJoin.joinChild = crmCandidate.candidateID)
LEFT JOIN crmJob ON (crmJob.jobID = crmJoin.joinParent)
LEFT JOIN crmDays ON (crmDays.dayCandidateID = crmJoin.joinChild)
WHERE
crmDays.dayJobID = crmJob.jobID AND
crmDays.dayCandidateID = crmCandidate.candidateID
GROUP BY
crmCandidate.candidateID
ORDER BY DESC
LIMIT 100
try this one :
SELECT
crmCandidate.candidateID,
crmCandidate.candidateName,
COUNT(DISTINCT crmJoin.joinID) AS Jobs,
Sum(Case When crmJoin.joinExtra = 'select' Then 1 else 0 end) as Selected,
Sum(Case When crmJoin.joinExtra = 'winner' Then 1 else 0 end) as winner,
ROUND(SUM(crmDays.total)) AS totalDays
FROM crmCandidate
LEFT JOIN crmJoin
ON crmJoin.joinChild = crmCandidate.candidateID
LEFT JOIN crmJob
ON crmJob.jobID = crmJoin.joinParent
Inner JOIN crmDays
On crmDays.dayCandidateID = crmCandidate.candidateID
AND crmDays.dayJobID = crmJob.jobID
GROUP BY crmCandidate.candidateID, crmCandidate.candidateName
ORDER BY candidateID DESC
LIMIT 100
The best thing to do is to aggregate the data before you do the join. You can probably do what you want with the following count(distinct) clauses:
COUNT(DISTINCT case when crmJoin.joinExtra = 'select' then crmJoin.JoinId end) AS Selected,
COUNT(DISTINCT case when crmJoin.joinExtra = 'winner' then crmJoin.JoinId end) AS Winner,

MySQL COUNT() to return 0

I have a query that looks like this:
SELECT
app.application_id,
j.job_number,
j.job_id,
j.job_title,
j.job_city,
j.job_state,
p.person_id AS candidate_id,
p.first_name,
p.last_name,
app.start_date,
ope1.percent_complete,
MAX(CASE
WHEN r.role_display_name = 'ENG - Recruiter' THEN
(SELECT CASE WHEN COUNT(last_name) = 0 THEN
'Unassigned'
ELSE
COUNT(last_name)
END AS uname
FROM users
JOIN job_roles ON job_roles.user_id = users.user_id
WHERE job_id = j.job_id
AND role_id = r.role_id
)
ELSE '' END) AS role_3
My problem is that COUNT(last_name) will not return 0, because there are no records returned, so there is no value of NULL. All makes sense, however I have tried wrapping it in IFNULL(), ISNULL() and none of them seem to fix this problem. How can I get it to return 0 when there are no records? Do I need another subquery inside the COUNT() aggregate? I would really like to not use another subquery....
If understand correctly what you want you can try to rewrite it this way
SELECT ...
,MAX(CASE WHEN r.role_display_name = 'ENG - Recruiter'
THEN COALESCE(NULLIF(
(
SELECT COUNT(last_name)
FROM users JOIN job_roles
ON job_roles.user_id = users.user_id
WHERE job_id = j.job_id
AND role_id = r.role_id
), 0), 'Unassigned')
ELSE ''
END) as role_3
...