SELECT branches.brid,
COALESCE(a.cnt, 0) AS Assigned,
COALESCE(c.cnt, 0) AS Completed,
COALESCE(p.cnt, 0) AS Pending,
COALESCE(x.cnt, 0) AS Expired
FROM branches WHERE access = 'User'
LEFT JOIN
(SELECT brid, count(*) from task GROUP BY brid) a ON branches.brid = a.brid
LEFT JOIN
(SELECT brid, count(*) from task WHERE stat = 'Completed' GROUP BY brid) c ON branches.brid = c.brid
LEFT JOIN
(SELECT brid, count(*) from task WHERE stat = 'Pending' GROUP BY brid) p ON branches.brid = p.brid
LEFT JOIN
(SELECT brid, count(*) from task WHERE stat = 'Expired' GROUP BY brid) x ON branches.brid = x.brid
ORDER BY branches.brid ASC;
I got this error when i create view is there any way to do this? this query works but i can't create view in my data base
ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause
The error more or less explains itself.
Here is an excerpt from the documentation, you need to run MySQL 5.7.7 or newer to be able to use a subquery in a view.
view definition is subject to the following restrictions:
Before MySQL 5.7.7, the SELECT statement cannot contain a subquery
in the FROM clause.
....
You can probably rewrite your query to something like this:
SELECT branches.brid,
COUNT(t.stat) AS Assigned,
SUM(CASE WHEN t.stat = 'Completed' THEN 1 ELSE 0 END) AS Completed,
SUM(CASE WHEN t.stat = 'Pending' THEN 1 ELSE 0 END) AS Pending,
SUM(CASE WHEN t.stat = 'Expired' THEN 1 ELSE 0 END) AS Expired
FROM branches
LEFT JOIN task t ON branches.brid = t.brid
WHERE access = 'User'
GROUP BY branches.brid
ORDER BY branches.brid ASC;
Related
I have this pseudo SQL code for what I want to achieve:
UPDATE orders o
SET o.datePaid = null
WHERE
(
SELECT SUM(amount)
FROM transactions t
WHERE t.orderId = o.id
AND t.status = 'success'
AND t.type = 'refund'
)
>=
(
SELECT SUM(amount)
FROM transactions t
WHERE t.orderId = o.id
AND t.status = 'success'
AND t.type IN ('purchase', 'capture')
)
How would I do this in SQL?
I think your approach is interesting. Here is a more concise method:
UPDATE orders o
SET o.datePaid = null
WHERE (SELECT SUM(CASE WHEN t.type = 'refund' THEN amount
WHEN t.type IN ('purchase', 'capture') THEN -amount
END)
FROM transactions t
WHERE t.orderId = o.id AND
t.status = 'success'
) > 0;
Your query works fine as is. However it can be more optimally written using MySQL multi-table UPDATE syntax:
UPDATE orders o
LEFT JOIN (SELECT orderId,
COALESCE(SUM(CASE WHEN type = 'refund' THEN amount END), 0) AS refunds,
COALESCE(SUM(CASE WHEN type IN ('purchase', 'capture') THEN amount END), 0) AS pc
FROM transactions
WHERE status = 'success'
GROUP BY orderId) t ON t.orderId = o.id
SET o.datePaid = NULL
WHERE t.refunds > t.pc
Demo on dbfiddle (includes your query working as well)
Your code would probably work just as it is. Give it a try.
You could also optimize the query to avoid the need for two subqueries by using a JOIN and conditional aggregation in a single subquery:
UPDATE orders o
INNER JOIN (
SELECT orderId
FROM transactions
WHERE
status = 'success'
AND type IN ('success', 'purchase', 'capture') -- this condition might be superfuous
GROUP BY o.id
HAVING
SUM(CASE WHEN type = 'success' THEN amount ELSE 0 END)
>= SUM(CASE WHEN type IN ('purchase', 'capture') THEN amount ELSE 0 END)
) t ON t.orderId = o.id
SET o.datePaid = null
Note: WHERE condition AND type IN ('success', 'purchase', 'capture') is superfluous if that list of 3 values represents all the possible values.
In my application the users can create campaigns for sending messages. When the campaign tries to send a message, one of the three things can happen:
The message is suppressed and not let through
The message can't reach the recipient and is considered failed
The message is successfully delivered
To keep track of this, I have the following table:
My problem is that when the application has processed a lot of messages (more than 10 million), the query I use for showing campaign statistics for the user slows down by a considerable margin (~ 15 seconds), even when there are only a few (~ 10) campaigns being displayed for the user.
Here is the query I'm using:
select `campaigns`.*, (select count(*) from `processed_messages`
where `campaigns`.`id` = `processed_messages`.`campaign_id` and `status` = 'sent') as `messages_sent`,
(select count(*) from `processed_messages` where `campaigns`.`id` = `processed_messages`.`campaign_id` and `status` = 'failed') as `messages_failed`,
(select count(*) from `processed_messages` where `campaigns`.`id` = `processed_messages`.`campaign_id` and `status` = 'supressed') as `messages_supressed`
from `campaigns` where `user_id` = 1 and `campaigns`.`deleted_at` is null order by `updated_at` desc;
So my question is: how can I make this query run faster? I believe there should be some way of not having to use sub-queries multiple times but I am not very experienced with MySQL syntax yet.
You should write this as a single join, using conditional aggregation:
SELECT
c.*,
COUNT(CASE WHEN pm.status = 'sent' THEN 1 END) AS messages_sent,
COUNT(CASE WHEN pm.status = 'failed' THEN 1 END) AS messages_failed,
COUNT(CASE WHEN pm.status = 'suppressed' THEN 1 END) AS messages_suppressed
FROM campaigns c
LEFT JOIN processed_messages pm
ON c.id = pm.campaign_id
WHERE
c.user_id = 1 AND
c.deleted_at IS NULL
GROUP BY
c.id
ORDER BY
c.updated_at DESC;
It should be noted that at first glance, doing SELECT c.* appears to be a violation of the GROUP BY rules which say that only columns which appear in the GROUP BY clause can be selected. However, assuming that campaigns.id is the primary key column, then there is nothing wrong with selecting all columns from this table, provided that we aggregate by the primary key.
Edit:
If the above answer does not run on your MySQL server version, with an error message complaining about only full group by, then use this version:
SELECT c1.*, c2.messages_sent, c2.messages_failed, c2.message_suppressed
FROM campaigns c1
INNER JOIN
(
SELECT
c.id
COUNT(CASE WHEN pm.status = 'sent' THEN 1 END) AS messages_sent,
COUNT(CASE WHEN pm.status = 'failed' THEN 1 END) AS messages_failed,
COUNT(CASE WHEN pm.status = 'suppressed' THEN 1 END) AS messages_suppressed
FROM campaigns c
LEFT JOIN processed_messages pm
ON c.id = pm.campaign_id
WHERE
c.user_id = 1 AND
c.deleted_at IS NULL
GROUP BY
c.id
) c2
ON c1.id = c2.id
ORDER BY
c2.updated_at DESC;
In below query (Mentors) are 13 which shows me 26, while (SchoolSupervisor) are 5 which shows me 10 which is wrong. it is because of the Evidence which having 2 evidance, because of 2 evidence the Mentors & SchoolSupervisor values shows me double.
please help me out.
Query:
select t.c_id,t.province,t.district,t.cohort,t.duration,t.venue,t.v_date,t.review_level, t.activity,
SUM(CASE WHEN pr.p_association = "Mentor" THEN 1 ELSE 0 END) as Mentor,
SUM(CASE WHEN pr.p_association = "School Supervisor" THEN 1 ELSE 0 END) as SchoolSupervisor,
(CASE WHEN count(file_id) > 0 THEN "Yes" ELSE "No" END) as evidence
FROM review_m t , review_attndnce ra
LEFT JOIN participant_registration AS pr ON pr.p_id = ra.p_id
LEFT JOIN review_files AS rf ON rf.training_id = ra.c_id
WHERE 1=1 AND t.c_id = ra.c_id
group by t.c_id, ra.c_id order by t.c_id desc
enter image description here
You may perform the aggregations in a separate subquery, and then join to it:
SELECT
t.c_id,
t.province,
t.district,
t.cohort,
t.duration,
t.venue,
t.v_date,
t.review_level,
t.activity,
pr.Mentor,
pr.SchoolSupervisor,
rf.evidence
FROM review_m t
INNER JOIN review_attndnce ra
ON t.c_id = ra.c_id
LEFT JOIN
(
SELECT
p_id,
COUNT(CASE WHEN p_association = 'Mentor' THEN 1 END) AS Mentor,
COUNT(CASE WHEN p_association = 'School Supervisor' THEN 1 END) AS SchoolSupervisor,
FROM participant_registration
GROUP BY p_id
) pr
ON pr.p_id = ra.p_id
LEFT JOIN
(
SELECT
training_id,
CASE WHEN COUNT(file_id) > 0 THEN 'Yes' ELSE 'No' END AS evidence
FROM review_files
GROUP BY training_id
) rf
ON rf.training_id = ra.c_id
ORDER BY
t.c_id DESC;
Note that this also fixes another problem your query had, which was that you were selecting many columns which did not appear in the GROUP BY clause. Under this refactor, there is nothing wrong with your current select, because the aggregation take place in a separate subquery.
try adding this to the WHERE part of your query
AND pr.p_id IS NOT NULL AND rf.training_id IS NOT NULL
You can add a group by pr.p_id to remove the duplicate records there. Since, the group by on pr is not present as of now, there might be multiple records of same p_id for same ra
group by t.c_id, ra.c_id, pr.p_id order by t.c_id desc
everyone.
I am using grails 3.3.0.M2 framework with mysql as data-source the following sql query is working as expected
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) 'open',
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) 'in progress',
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) 'closed'
FROM
tickets t
INNER JOIN
users u ON t.user_id = u.id
INNER JOIN
user_coordinations uc ON uc.user_id = u.id
INNER JOIN
coordinations c ON c.id = uc.coordination_id
GROUP BY 1
I translated to HQL using implicit JOIN but I am getting the wrong results, here is the hql query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t, User u, UserCoordination uc, Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
In order to get the right results stack overflow users help me to understand that the query needs to use explicit JOINS, here the question: Group by a field that does not belongs to the consulted table
Right now I am trying with the following query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t
INNER JOIN
User u
INNER JOIN
UserCoordination uc
INNER JOIN
Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
But i am getting a com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException with the caused message You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'inner join user_coordinations usercoordi2_ on inner join coordinations coordinat' at line 1
Thanks for your help and time
SELECT new map(
c.name as name,
(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) as open,
(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) as pending,
(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) as closed,
SUM(open) as openSum,
SUM(pending) as pendingSum,
SUM(closed) as closedSum
)
FROM
Ticket t
left join t.user u left join u.userCoordination uc left join uc.coordination c
WHERE
MONTH(t.dateCreated) = :month
//GROUP BY 1
What you had had lots missing above is more like what you need, you need
select new map(i.item as item... if you compare the basics of this with what you had and what i tried to do you can see why you had errors.
unsure about your group by it should be group by something. Wasn't sure by inner join if you just meant a join if that was the case leave out all the left join since left join attempts to connect and get any null hasMany relations etc.
I have some trouble to count more than 2 counts in mysql statement.
My count(b.entry_id) as totalbooking wont work. What have i done wrong? Is the statement setup also correctly made?
This is how i tried:
"SELECT
t.restaurant_id as restaurant_id, ct.title as title,
count(DISTINCT t.cardid) as totalmembers,
count(t.restaurant_id) as totaltransactions,
count(b.entry_id) as totalbooking
from transactions as t
inner join exp_menucard_booking as b on (t.restaurant_id = b.entry_id)
inner join exp_channel_titles as ct on (t.restaurant_id = ct.entry_id)
inner JOIN exp_channel_data as cd on (ct.entry_id = cd.entry_id)
where t.cardid != 88888888 and ct.status = 'open'
group by t.restaurant_id
order by ct.title asc";
Use this pattern to count subsets of the total rowset:
sum( case when ColumnToBeTested = trueCondition then 1 else 0 end) as SubCount