Case condition is not working - mysql

What I need:
I need to check if eventvisitor.published is 1 then increment by zero else eventvisitor is equal to 0.
mysql query
SUM(
CASE
WHEN eventvisitor.published =1
THEN eventvisitor.published=eventvisitor.published+0
ELSE eventvisitor.published=0
END
) AS eventvsisitorpublished
sql query works
$qb->select('
eve.id,
SUBSTRING(ed.value,1,150) des,
eve.membership,
eve.name,
eve.abbrName abbr_name,
eve.membership paid,
eve.wrapper event_wrapper,
(case when attach.cdnUrl is null then attach.value else attach.cdnUrl end) event_samll_wrapper,
eve.url event_url,
eve.website,
eve.eventType,
venue.name venue_name,
e.startDate,
e.endDate,
ct.name city,
c.name country,
c.url country_url,
c.shortname country_shortname,
category.id industry_id,
category.name industry_name,
category.url industry_url,
eve.status event_status,
count(distinct eventvisitor.user) PeopleAttending
')
->add('from', $from);
->innerJoin('Entities\City','ct','with','eve.city = ct.id')
->innerJoin('Entities\Country','c','with','eve.country = c.id')
->innerJoin('Entities\EventEdition','e','with','eve.eventEdition = e.id')
->innerjoin('Entities\EventCategory','cat','with','e.event = cat.event')
->innerjoin('Entities\Category','category','with','cat.category = category.id')
->leftJoin('Entities\Venue','venue','with','e.venue=venue.id')
->leftJoin('Entities\EventVisitor','eventvisitor','with','eve.id=eventvisitor.event')
//->leftJoin('Entities\Venue','v','with','v.id = e.venue')
->leftJoin('Entities\EventData','ed','with','eve.eventEdition = ed.eventEdition')
->leftJoin('Entities\Attachment','attach','with','eve.wrapperSmall = attach.id')
->Where("ed.title ='desc' or ed.title is null")
->andWhere("eve.id in (".$res.")")
->andWhere("eventvisitor.published =1")
works check in where condition.
problem I'm facing: I'm getting 500 internal error
where I have done wrong any suggestion are most welcome.

use this
SUM(
IF(eventvisitor.published ==1, eventvisitor.published , 0)
) AS eventvsisitorpublished

Related

MySQL - Slow Query when adding multiple derived tables - Optimization

For my query, the two derived tables at the bottom are causing a crazy slow up for this query. The query, as is, takes about 45-55 seconds to execute.. NOW, when i remove just one of those derived tables (it does not matter which one) the query goes down to 0.1 - 0.3 seconds. My questions; Is there an issue with having multiple derived tables? Is there a better way to execute this? My indexes all seem to be correct, I will also include the explain from this query.
select t.name as team, u.name as "REP NAME",
count(distinct activity.id) as "TOTAL VISITS",
count(distinct activity.account_id) as "UNIQUE VISITS",
count(distinct placement.id) as "COMMITMENTS ADDED",
CASE WHEN
count(distinct activity.account_id) = 0 THEN (count(distinct
placement.id) / 1)
else (cast(count(distinct placement.id) as decimal(10,2)) /
cast(count(distinct activity.account_id) as decimal(10,2)))
end as "UNIQUE VISIT TO COMMITMENT %",
case when o.mode='basic' then count(distinct placement.id) else
count(distinct(case when placement.commitmentstatus='fullfilled'
then placement.id else 0 end))
end as "COMMITMENTS FULFILLED",
case when o.mode='basic' then 1 else
(CASE WHEN
count(distinct placement.id) = 0 THEN (count(distinct(case when
placement.commitmentstatus='fullfilled' then placement.id else 0
end)) / 1)
else (cast(count(distinct(case when
placement.commitmentstatus='fullfilled' then placement.id else 0
end)) as decimal(10,2)) / cast(count(distinct placement.id) as
decimal(10,2)))
end) end as "COMMITMENT TO FULFILLMENT %"
from lpmysqldb.users u
left join lpmysqldb.teams t on t.team_id=u.team_id
left join lpmysqldb.organizations o on o.id=t.org_id
left join (select * from lpmysqldb.activity where
org_id='555b918ae4b07b6ac5050852' and completed_at>='2018-05-01' and
completed_at<='2018-06-01' and tag='visit' and accountname is not
null and (status='active' or status='true' or status='1')) as
activity on activity.user_id=u.id
left join (select * from lpmysqldb.placements where
orgid='555b918ae4b07b6ac5050852' and placementdate>='2018-05-01' and
placementdate<='2018-06-01' and (status IN ('1','active','true') or
status is null)) as placement on placement.userid=u.id
where u.org_id='555b918ae4b07b6ac5050852'
and (u.status='active' or u.status='true' or u.status='1')
and istestuser!='1'
group by u.org_id, t.name, u.id, u.name, o.mode
order by count(distinct activity.id) desc
Thank you for assistance!
I have edited below with changing the two bottom joins from joining on subqueries to joining on the table directly. Still yielding the same result.
This is a SLIGHTLY restructured query of your same. Might be simplified as the last two subqueries are all pre-aggregated for your respective counts and count distincts so you can use those column names directly instead of showing all the count( distinct ) embedded throughout the query.
I also tried to simplify the division by multiplying a given count by 1.00 to force decimal-based precision as result.
select
t.name as team,
u.name as "REP NAME",
Activity.DistIdCnt as "TOTAL VISITS",
Activity.UniqAccountCnt as "UNIQUE VISITS",
Placement.DistIdCnt as "COMMITMENTS ADDED",
Placement.DistIdCnt /
CASE WHEN Activity.UniqAccountCnt = 0
THEN 1.00
ELSE Activity.UniqAccountCnt * 1.00
end as "UNIQUE VISIT TO COMMITMENT %",
case when o.mode = 'basic'
then Placement.DistIdCnt
else Placement.DistFulfillCnt
end as "COMMITMENTS FULFILLED",
case when o.mode = 'basic'
then 1
else ( Placement.DistFulfillCnt /
CASE when Placement.DistIdCnt = 0
then 1.00
ELSE Placement.DistIdCnt * 1.00
END TRANSACTION )
END as "COMMITMENT TO FULFILLMENT %"
from
lpmysqldb.users u
left join lpmysqldb.teams t
on u.team_id = t.team_id
left join lpmysqldb.organizations o
on t.org_id = o.id
left join
( select
user_id,
count(*) as AllRecs,
count( distinct id ) DistIdCnt,
count( distinct account_id) as UniqAccountCnt
from
lpmysqldb.activity
where
org_id = '555b918ae4b07b6ac5050852'
and completed_at>='2018-05-01'
and completed_at<='2018-06-01'
and tag='visit'
and accountname is not null
and status IN ( '1', 'active', 'true')
group by
user_id ) activity
on u.id = activity.user_id
left join
( select
userid,
count(*) AllRecs,
count(distinct id) as DistIdCnt,
count(distinct( case when commitmentstatus = 'fullfilled'
then id
else 0 end )) DistFulfillCnt
from
lpmysqldb.placements
where
orgid = '555b918ae4b07b6ac5050852'
and placementdate >= '2018-05-01'
and placementdate <= '2018-06-01'
and ( status is null OR status IN ('1','active','true')
group by
userid ) as placement
on u.id = placement.userid
where
u.org_id = '555b918ae4b07b6ac5050852'
and u.status IN ( 'active', 'true', '1')
and istestuser != '1'
group by
u.org_id,
t.name,
u.id,
u.name,
o.mode
order by
activity.DistIdCnt desc
FINALLY, your inner queries are querying for ALL users. If you have a large count of users that are NOT active, you MIGHT exclude those users from each inner query by adding those join/criteria there too such as...
( ...
from
lpmysqldb.placements
JOIN lpmysqldb.users u2
on placements.userid = u2.id
and u2.status IN ( 'active', 'true', '1')
and u2.istestuser != '1'
where … ) as placement

MySQL Procedures behaving weird once variables are inserted

I'm having a frustrating time with MySQL and a procedure I'm writing and wanted to see if anyone else had any clues as to what is going on.
The procedure I have below will dynamically transpose rows in a table to columns. It is working perfectly except for the very last WHERE statement.
If I have either of the following WHERE statements it works fine.
WHERE t.company_id = v_company_id AND t.class = 'asset_property'
WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'
However, if I also want to grab records where the company_id could be 1 OR whatever value is passed in, it refuses to run. The only change made to the query is to the 'WHERE` statement. None of these versions will work.
WHERE (t.company_id = v_company_id OR t.company_id = 1) AND t.class = 'asset_property'
WHERE t.company_id IN (v_company_id, 1) AND t.class = 'asset_property'
WHERE t.company_id IN (161, 1) AND t.class = 'asset_property'
Appreciate any assistance that someone more versed in MySQL can provide. I've tried debugging as best I can and the only error I can seem to find is that when I try to get t.company_id to be one of two values, there is a generic error saying Invalid table name.
The full procedure is below.
(See Update 1)
Finally, if I generate the working statement above, then manually add in the lines for t.company_id = 1 records, it works perfectly and creates the following query.
(See Update 1)
Update 1
So that others can simulate what I'm seeing, I've built a test DB with test data in it so you can try this yourself. Also removing some of the code above to save space...
Trying to add this here blew out my character limit. I've uploaded it to my personal site. (Please let me know if this is not a safe thing to do!)
Test DB
Once you've created this DB, here are some procedures and SQL statements that you can run to test it and simulate what I'm doing.
The Procedure fill_tableau_ap that is in the Test DB will run and will create a table with the data in it (but is missing the company 1 records).
That Procedure generates the following SQL:
CREATE TABLE dw_161.tableau_ap AS
SELECT a.id as "Asset ID (ap)",
max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN"
FROM dw_161.equipment AS a
JOIN dw_161.asset_properties ap ON ap.asset_id = a.id
JOIN dw_161.sites AS s on a.site_id = s.id
WHERE dw_161.s.company_id = 161
GROUP BY a.id;
If I manually, add in a single item from company 1 into that above statement as below, I can run this on the DB and it also works. Here's what it looks like in case you also want to run it on the Test DB.
CREATE TABLE dw_161.tableau_ap AS
SELECT a.id as "Asset ID (ap)",
max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
## Next field added manually from company 1 into the query
max(case when ap.property_id = 213 then ap.numeric_value else null end) as "Odometer" ,
max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN"
FROM dw_161.equipment AS a
JOIN dw_161.asset_properties ap ON ap.asset_id = a.id
JOIN dw_161.sites AS s on a.site_id = s.id
WHERE dw_161.s.company_id = 161
GROUP BY a.id;
So we can conclude, that if I can get the statement generated correctly, it will run and work. So it must be a problem with the statement generation.
Breaking the procedure into parts, there is the second half that feeds the list of Asset Properties into the first half. That's where I think things are going haywire. Specifically, in this section of the Procedure:
SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'
ORDER BY ap_name
So what happens if I pull out the variable v_company_id and manually enter what I am ultimately look for and run this, as follows? Well naturally it works and provides a list of all the asset properties. (there are no duplicates here.)
SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (161,1) AND t.class = 'asset_property'
ORDER BY ap_name
Update 2
ARGH!!! Whilst going through all of this and making sure that it was completely repeatable for others looking at it, I noticed one of the fields was registered as decimal in the DB when we store both numeric and decimal data in a single field called numeric_value in the table. That ulitimately was my problem and I appeared to have Rubber Ducked myself. Changing the procedure to translate any fields stored in the DB to the actual column names solved my problem!
Here is the finished procedure in case anyone is interested. It's an interesting bit of code for transposing rows into columns in a DB if others need that.
BEGIN
SET #sql = concat('DROP TABLE IF EXISTS dw_', v_company_id, '.tableau_ap;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET SESSION group_concat_max_len = 1000000;
SET #sql = (select concat('CREATE TABLE dw_', v_company_id, '.tableau_ap AS SELECT a.id as "Asset ID (ap)", ',
group_concat(
concat('max(case when ap.property_id = ',ap_id, ' then ap.', ap_data_type, '_value else null end) as "', ap_name,'" ')
),
'FROM dw_', v_company_id, '.equipment AS a ',
'JOIN dw_', v_company_id, '.asset_properties ap ON ap.asset_id = a.id ',
'JOIN dw_', v_company_id, '.sites AS s on a.site_id = s.id ',
'WHERE dw_', v_company_id, '.s.company_id = ', v_company_id,' ',
'GROUP BY a.id;'
)
from
(
SELECT i.id as ap_id, item as ap_name,
(CASE asset_property_data_type
WHEN 'numeric' THEN 'numeric'
WHEN 'decimal' THEN 'numeric'
WHEN 'calculated' THEN 'numeric'
WHEN 'text' THEN 'text'
WHEN 'date' THEN 'date'
WHEN 'asset' THEN 'id'
WHEN 'employee' THEN 'id'
WHEN 'bar-code' THEN 'text'
WHEN 'currency' THEN 'numeric'
WHEN 'time' THEN 'date'
WHEN 'duration' THEN 'date'
WHEN 'serial' THEN 'text'
END) AS ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (v_company_id,1) AND t.class = 'asset_property'
ORDER BY ap_name) a
)
;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
See Update 2 above in the original post.

SQL count when value = 1

I'm doing a select on two tables with this:
SELECT m.torneio, m.deck, m.top, m.lugar, sum( m.quantidade ) AS quantidade, m.formato AS formato, q.quantidade AS qtorneio, t.season AS season, sum( m.top ) AS totaltops, count( m.lugar = '1' ) AS venceu
FROM `metagame` AS m, quantidade AS q, torneios AS t
WHERE m.torneio = t.nome
AND m.torneio = q.nome
GROUP BY m.deck
My problem is that venceu is counting all instances instead of only the ones when lugar = 1. Why is that?
tried with sum() too with no good results too. How can i fix this?
I am surprised that count( m.lugar = '1' ) syntaxs but it does and returns the sames as count(*). You should probably change it to sum(case when lugar = 1 else 0 end) as venceu. You should also look closely at the group by to be sure it works as you expect (i suspect not).
count(x) does not accept an expression.
It's only counting how many times x is returned.
What you should do is check if m.lugar is 1 and yes add one to the counter else do nothing.
Inline checks can be done like so:
case when m.lugar = '1' then 1 else 0 end
Then add all the one you gets :
sum(case when m.lugar = '1' then 1 else 0 end)
Your final query should look like this:
SELECT
m.torneio,
m.deck,
m.top,
m.lugar,
sum( m.quantidade ) AS quantidade,
m.formato AS formato,
q.quantidade AS qtorneio,
t.season AS season,
sum( m.top ) AS totaltops,
sum(case when m.lugar = '1' then 1 else 0 end) AS venceu
FROM
`metagame` AS m,
quantidade AS q,
torneios AS t
WHERE
m.torneio = t.nome
AND m.torneio = q.nome
GROUP BY
m.deck
If I understand your question you can use this:
sum(case when m.lugar = '1' then 1 else 0 end)
or you can try having clause
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
HAVING condition
ORDER BY column_name(s);

Doctrine 2 DQL CASE WHEN in Count

I have this Query in native MySQL Code
SELECT *
FROM `turn`
LEFT JOIN (
poi
) ON ( turn.id = poi.turn_id )
GROUP BY turn.id
ORDER BY count( case when poi.image = 1 then 1 else null end) DESC;
I need to rebuild this in Doctrine 2 DQL
My attempt so far is this:
SELECT t, COUNT((CASE WHEN Bundle\Entity\Poi p.image = 1 then 1 ELSE NULL END)) AS num
FROM Bundle\Entity\Turn t
JOIN t.pois p
GROUP BY t.id
ORDER BY num DESC
And im getting this error:
An exception has been thrown during the rendering of a template ("[Syntax Error] line 0, col 99: Error: Expected end of string, got '.'") in Bundle:Admin:showTurnsFiltered.html.twig at line 75.
What am i doing wrong?
I found it by myself after hours of trying and searching, it's working with this DQL:
$dql = 'SELECT t,
SUM(CASE WHEN p.image = 1 THEN 1 ELSE 0 END) AS numImage
FROM Bundle\Entity\Turn t
JOIN t.pois p
GROUP BY t.id
ORDER BY numImage DESC';
Important that you need to use SUM instead of COUNT
You need to use ResultSetMappingBuilder. It would look something like :
public function getTurn()
{
$rsm = new ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata('Foo\BarBundle\Entity\Turn', 't');
$rsm->addJoinedEntityFromClassMetadata('Foo\BarBundle\Entity\Poi', 'p', 't', 'poi', array('id' => 'poi_id'));
$rsm->addScalarResult('ImageCount', 'ImageCount');
$sql = 'SELECT t.id, t.foo, t.bar,
SUM(CASE WHEN p.image = 1 then 1 else null end) ImageCount,
FROM Turn t
INNER JOIN poi p ON t.id = p.turn_id
ORDER BY ImageCount DESC';
$query = $this->_em->createNativeQuery($sql, $rsm);
return $query->getScalarResult();
}
note: you might need to change $query->getScalarResult()to $query->getResult().

How to get separate fields data with IF() statement in single query

I am trying to get the unpaid and partial amount separately in single query
select
if(i.status = 'unpaid', sum(i.total_amount), '') unpaid,
if(i.status = 'partial', sum(i.paid_amount), '') partial
from {CI}invoices i
where
i.customer_id = ? and
date(i.invoice_date) < '2014-01-01' and
i.status not like 'paid%'
But i am getting blank i think that is because i used '' in if statement, i also tried with
if(i.status = 'unpaid', sum(i.total_amount) as unpaid, sum(i.paid_amount) as paid)
which is wrong because i can't use as in IF() condition. Can anyone please help me to resolve this query or suggest any alternative way??
Try the following:
SELECT
SUM( IF(i.status = 'unpaid', i.total_amount, 0) ) unpaid,
SUM( IF(i.status = 'partial', i.paid_amount, 0) ) partial
FROM {CI}invoices i
WHERE
i.customer_id = ? AND
date(i.invoice_date) < '2014-01-01' AND
i.status IN ('unpaid', 'partial')
Give this a go:
select
sum(case when i.status = 'unpaid' then i.total_amount else 0 end) as unpaid,
sum(case when i.status = 'partial' then i.paid_amount else 0 end) as partial
from {CI}invoices i
where
i.customer_id = ? and
date(i.invoice_date) < '2014-01-01' and
i.status not like 'paid%'
You have to cross join table to itself to get paid and unpaid in the same row:
SELECT
sum(iu.total_amount) unpaid,
sum(ip.paid_amount) partial
FROM {CI}invoices iu
CROSS JOIN {CI}invoices ip
where
ip.customer_id = ? AND iu.customer_id = ? AND
date(ip.invoice_date) < '2014-01-01' AND date(iu.invoice_date) < '2014-01-01' AND
iu.status = 'unpaid' AND ip.status = 'partial'