I am currently writing a query.
Retrieves information from users, posts, and additional information tables in posts (post_views_info).
SELECT
u.email,
u.user_nm,
p.pid,
p.post_ttl,
p.date,
p.ref_level,
p.ref_origin,
p.ref_step,
date(p.date) = date(now()) AS is_today,
(SELECT category_path FROM post_category WHERE category_id = p.category_id) as category_full_path,
(SELECT COUNT(*) FROM post_status_info AS sub_i WHERE sub_i.pid = p.pid AND sub_i.status = 'A') AS recommendCount,
(SELECT COUNT(*) FROM post_status_info AS sub_i WHERE sub_i.pid = p.pid AND sub_i.status = 'B') AS oppositeCount,
(SELECT COUNT(*) FROM post_status_info AS sub_i WHERE sub_i.pid = p.pid AND sub_i.status = 'C') AS reportCount
FROM
(
SELECT *
FROM post as p
WHERE
p.is_enable = 1
ORDER BY
p.ref_origin DESC,
p.ref_step ASC
) as p,
user AS u
WHERE
p.uid = u.uid
ORDER BY
ref_origin DESC,
ref_step ASC
In the above query, we query the same table three times to get the number of posts 'A', 'B', 'C'.
To solve this problem, I changed the query as follows.
SELECT
u.email,
u.user_nm,
p.pid,
p.post_ttl,
p.date,
p.ref_level,
p.ref_origin,
psi.reportCount,
psi.recommendCount,
psi.oppositeCount,
p.ref_step,
date(p.date) = date(now()) AS is_today,
(SELECT category_path FROM post_category WHERE category_id = p.category_id) as category_full_path
FROM
user AS u,
(
SELECT *
FROM post as p
WHERE
p.is_enable = 1
ORDER BY
p.ref_origin DESC,
p.ref_step ASC
LIMIT 0, 15
) as p left join
(
SELECT
pid,
COUNT(if(status = 'A', 1, null)) AS reportCount,
COUNT(if(status = 'B', 1, null)) AS recommendCount,
COUNT(if(status = 'C', 1, null)) AS oppositeCount
FROM post_status_info
group by pid
) AS psi
on
psi.pid = p.pid
WHERE
p.uid = u.uid
ORDER BY
ref_origin DESC,
ref_step ASC
I think it would be better to query the same table three times.
Which code is better in terms of performance?
Thanks.
I think second option is more fruitful in terms of performance. Because here we have less number of queries to execute.
You can also do it by using CASE.
SELECT
u.email,
u.user_nm,
p.pid,
p.post_ttl,
p.date,
p.ref_level,
p.ref_origin,
p.ref_step,
date(p.date) = date(now()) AS is_today,
(SELECT category_path FROM post_category WHERE category_id = p.category_id) as category_full_path,
(SUM(CASE WHEN sub_i.status = 'A' THEN 1 ELSE 0 END)) AS recommendCount,
(SUM(CASE WHEN sub_i.status = 'B' THEN 1 ELSE 0 END)) AS oppositeCount,
(SUM(CASE WHEN sub_i.status = 'C' THEN 1 ELSE 0 END)) AS reportCount
FROM
(
SELECT *
FROM post as p
WHERE
p.is_enable = 1
ORDER BY
p.ref_origin DESC,
p.ref_step ASC
) as p,
INNER JOIN user AS u ON u.uid = p.uid
INNER JOIN post_status_info as sub_i ON p.pid = sub_i.pid
GROUP BY p.pid
ORDER BY
ref_origin DESC,
ref_step ASC
Related
SELECT users.id, users.name,
(
SELECT coalesce(sum(games.point), 0)
from games
where games.point_type = 1
AND games.service_id = '9'
and games.user_id = users.id
) as earned,
(
SELECT coalesce(sum(games.point), 0)
from games
where games.point_type = 0
AND games.service_id = '9'
and games.user_id = users.id
) as awaiting,
(
SELECT coalesce(sum(games.point), 0)
from games
where games.point_type in (0, 1)
AND games.service_id = '9'
and games.user_id = users.id
) as total
FROM users, games
WHERE users.id = games.user_id
AND games.service_id = '9'
AND users.deleted_at IS NULL
GROUP BY users.id, users.name
ORDER BY total DESC
Hi, I'm a new user for SqlAlchemy, and it's my raw sql with postgresql, is it possible to work with SqlAlchemy?
I've tried search with subquery, but it's like query after From query...
I'm writing code for the production report.
I had written this query
SELECT
P.*,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_prod,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_dispatched,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production_dispatched,
C.name AS category_name
FROM
products P
INNER JOIN category C ON
C.id = P.category
This query is working but as I have too many records in all tables it takes too much time.
also, I need only records where before_prod, before_dispatched, production, production_dispatched all these subquery results should be greater than 0.
I tried to use having clause but it also takes too much time.
I have also tried php for loop, * LOGIC: first all products than in for loop its production. but it was much slower.*
How can I optimize my query?
You can use join instead and select case to sum your data that matches your conditions.
select p.*, t.*
from products p
inner join (
select t2.id, sum(case when create_date < '2019-11-01' then 1 else 0 end) as before_prod
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date < '2019-11-01' then 1 else 0 end) as before_dispatched
, sum(case when create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production_dispatched
from bales t1
inner join product t2 on t2.id= t1.product_id
inner join category t3 on t3.id = t2.category
where t1.TYPE in ('bale', 'bag')
group by t2.id) t
on t.id = p.id
I have a MySQL query and it takes about 25 sec. There are not many rows (just about 200) but I don't understand why it takes long time.
Query:
SELECT *
, c.id c_id
FROM campaign c
JOIN campaign_category cc
ON c.campaign_type = cc.id
WHERE c.is_deleted = 0
AND c.status = 1
AND c.id NOT IN (SELECT campaign_id FROM user_reviews WHERE user_id = 4)
AND c.amt_req > (SELECT COUNT(id)
FROM reserved_reviews
WHERE camping_id = c.id
AND user_id != 4)
+ (SELECT COUNT(id)
FROM user_reviews
WHERE campaign_id = c.id)
Edit:
I tried with JOIN like this but i got no result:
SELECT
*, `c`.`id` as `c_id`,COUNT(`ur`.`id`) as `total_reviewed`, COUNT(`rr`.`id`) as `total_reserved`
FROM
`campaign` `c`
JOIN `campaign_category` `cc` ON `c`.`campaign_type`=`cc`.`id`
JOIN `user_reviews` `ur` ON `ur`.`campaign_id`=`c`.`id`
JOIN `reserved_reviews` `rr` ON `rr`.`camping_id`=`c`.`id`
WHERE
`c`.`is_deleted` =0
AND
`c`.`status` = 1
AND
`ur`.`user_id` != 4
GROUP BY `c`.`id`
HAVING `c`.`amt_req` > COUNT(`ur`.`id`) + COUNT(`rr`.`id`)
Edit: Table structures: First Image - user_reviews Table, Second image campagin Table, Third image: reserved_reviews Table.
http://imgur.com/GI4817B,SdnSxuz,truxHM6#0
You can improve this query with indexes;
SELECT *, c.id c_id
FROM campaign c JOIN
campaign_category cc
ON c.campaign_type = cc.id
WHERE c.is_deleted = 0 AND
c.status = 1 AND
c.id NOT IN (SELECT campaign_id FROM user_reviews WHERE user_id = 4)
c.amt_req > (SELECT COUNT(*)
FROM reserved_reviews
WHERE campaign_id = c.id AND user_id <> 4)
) +
(SELECT COUNT(id)
FROM user_reviews
WHERE campaign_id = c.id
) ;
For the outer query and joins: campaign(status, is_deleted, id, amt_req) and campaign_category(id) (you should have the latter if it is defined as a primary key.
Then: user_reviews(user_id, campaign_id), reserved_reviews(campaign_id, user_id), and user_reviews(campaign_id).
SELECT p . * , (
SELECT (
SELECT COUNT( * )
FROM sales s
WHERE s.affiliate != ''
AND s.pid = p.pid
AND s.saletype = 'sale' )
) AS popular
FROM products p
INNER JOIN members m ON m.uname = p.vendor
WHERE (m.mpid = p.pid OR p.marketavail = 'yes')
AND p.showinmarket = 'yes'
AND p.pname != ''
AND p.pdesc != ''
AND p.active = 'yes'
ORDER BY popular DESC
Here, If i use ORDER BY popular , it takes 17 seconds to load. without this ordering , query is executed in 4 seconds.
Please tell me why it is taking too much time while ordering by virtual columns?
All tables has index on required columns, so indexing is not the issue i guess. And if i run select count(*) for single product, it is executing in milliseconds.
And one more error i saw, If i remove SELECT word (second select word in my sql), it takes 105 sec to execute.
Please tell me if i need to give any more information.
Due to such delay in sorting, i am using php instead of mysql for sorting. Please help me to make it better.
Thank you in advance.
please try this query
SELECT p.column1,
p.column2,
p.column3,
COUNT(s.pid) as popular
FROM products p
INNER JOIN members m ON m.uname = p.vendor
LEFT JOIN sales s ON s.pid = p.pid AND s.affiliate != '' AND s.saletype = 'sale'
WHERE (m.mpid = p.pid OR p.marketavail = 'yes')
AND p.showinmarket = 'yes'
AND p.pname != ''
AND p.pdesc != ''
AND p.active = 'yes'
GROUP BY p.column1,p.column2,p.column3
ORDER BY popular DESC
column1,column2,column3 are just examples of columns you want, because you're select * I don't know what column names are from product. so change them to your actual column names.
edit: try this query see if it's any faster
SELECT p.pname, p.vendor, p.pid,
COUNT( s.pid ) AS popular
FROM products p INNER JOIN members m ON m.uname = p.vendor
LEFT JOIN
(SELECT pid FROM sales
WHERE affiliate != ''
AND saletype = 'sale'
)s
ON (s.pid = p.pid)
WHERE ( m.mpid = p.pid OR p.marketavail = 'yes' )
AND p.showinmarket = 'yes' AND p.pname != ''
AND p.pdesc != ''
AND p.active = 'yes'
GROUP BY p.pid, p.pname
ORDER BY popular DESC
if it runs faster you can pre-filter products too like this query and see if it runs even faster
SELECT p.pname, p.vendor, p.pid,
COUNT( s.pid ) AS popular
FROM (SELECT pname,vendor,pid,marketavail
FROM products
WHERE showinmarket = 'yes'
AND pname != ''
AND pdesc != ''
AND active = "yes"
)p
INNER JOIN members m ON m.uname = p.vendor
LEFT JOIN
(SELECT pid FROM sales
WHERE affiliate != ''
AND saletype = 'sale'
)s
ON (s.pid = p.pid)
WHERE ( m.mpid = p.pid OR p.marketavail = 'yes' )
GROUP BY p.pid, p.pname
ORDER BY popular DESC
I have this SQL statement:
SELECT
(CASE
WHEN EXISTS
(SELECT *
FROM votes
WHERE votes.user_id = 0
AND votes.post_id = posts.id
AND votes.vote = 0) THEN 0
WHEN EXISTS
(SELECT *
FROM votes
WHERE votes.user_id = 0
AND votes.post_id = posts.id
AND votes.vote = 1) THEN 1
ELSE 2
END) AS vote_by_me ,
posts.*
FROM `posts`
Is there a way I can do this in a DRY manner? Both select statements are almost the same, would be nice to factor them out some way.
Thanks
Yes, you can select votes.vote directly, like this:
SELECT
COALESCE(
(
SELECT MIN(votes.vote)
FROM votes
WHERE votes.user_id = 0 AND votes.post_id = posts.id
AND votes.vote in (0, 1)
GROUP BY votes.user_id, votes.post_id
)
, 2
) AS vote_by_me
, posts.*
FROM `posts
If a post cannot have multiple votes by the same user, you could eliminate the GROUP BY, like this:
SELECT
COALESCE(
(
SELECT votes.vote
FROM votes
WHERE votes.user_id = 0 AND votes.post_id = posts.id AND votes.vote in (0, 1)
)
, 2
) AS vote_by_me
, posts.*
FROM `posts
This would seem to simplify the query:
SELECT (CASE WHEN v.votes0 > 0 THEN 0
WHEN v.votes1 > 0 THEN 1
ELSE 2
END) AS vote_by_me,
p.*
FROM posts p left outer join
(select v.post_id, sum(v.vote = 1) as vote1, sum(v.vote = 0) as vote0
from votes v
where v.user_id = 0
group by v.post_id
) v
on p.post_id = v.post_id;
The bad news is that if you have an index on votes(user_id, post_id, votes) then your original form will probably have better performance.
EDIT:
The following formulation might perform well and sort-of simplify the query:
SELECT (CASE (SELECT min(vote)
FROM votes
WHERE votes.user_id = 0 AND
votes.post_id = posts.id
)
WHEN 0 then 0
WHEN 1 then 1
ELSE 2
END) AS vote_by_me,
posts.*
FROM `posts`;
SELECT
(CASE
WHEN EXISTS
(SELECT *
FROM votes
WHERE votes.user_id = 0
AND votes.post_id = posts.id
AND votes.vote IN (0,1) )THEN votes.vote
ELSE 2
END) AS vote_by_me ,
posts.*
FROM `posts`