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`
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 this query i am trying to optimize, I want to replace LIKE that is causing full table scan by a MATCH AGAIN command.
This is the original query, it is working great but too slow
SELECT DISTINCT a.*, (CASE WHEN a.title LIKE :keywords THEN 300 ELSE 0 END) +
(CASE WHEN a.title LIKE :word_0 THEN 10 ELSE 0 END) +
(CASE WHEN a.description LIKE :word_0 THEN 10 ELSE 0 END) +
(CASE WHEN cl.name LIKE :word_0 THEN 5 ELSE 0 END) +
(CASE WHEN cpl.name LIKE :word_0 THEN 2 ELSE 0 END) +
(CASE WHEN cl.description LIKE :word_0 THEN 1 ELSE 0 END) +
(CASE WHEN cpl.description LIKE :word_0 THEN 1 ELSE 0 END) as relevance,
FROM lara237posts as a
INNER JOIN lara237categories as c ON c.id=a.category_id AND c.active=1
LEFT JOIN lara237categories as cp ON cp.id=c.parent_id AND cp.active=1
LEFT JOIN (SELECT MAX(id) max_id, post_id FROM lara237payments WHERE active=1 GROUP BY post_id) mpy ON mpy.post_id = a.id AND a.featured=1
LEFT JOIN lara237payments as py ON py.id=mpy.max_id
LEFT JOIN lara237packages as p ON p.id=py.package_id
LEFT JOIN lara237categories as cl ON cl.translation_of=c.id AND cl.translation_lang = :translationLang
LEFT JOIN lara237categories as cpl ON cpl.translation_of=cp.id AND cpl.translation_lang = :translationLang
WHERE a.country_code = :countryCode AND (a.verified_email = 1 AND a.verified_phone = 1) AND a.archived != 1 AND a.deleted_at IS NULL AND a.reviewed = 1
GROUP BY a.id, relevance
HAVING relevance >= :average
ORDER BY p.lft DESC, relevance DESC, a.created_at DESC
LIMIT 0, 16
I have create the query below to replace Like by MATCH AGAIN, but the second query is giving me no result. I am wondering where the issue is ?
Below is the second query i have created
SELECT DISTINCT a.*, (CASE WHEN MATCH(a.title, a.description) AGAINST(:keywords IN NATURAL LANGUAGE MODE) THEN 300 ELSE 0 END) +
(CASE WHEN MATCH(cl.name) AGAINST(:word_0 IN NATURAL LANGUAGE MODE) THEN 5 ELSE 0 END) +
(CASE WHEN MATCH(cpl.name) AGAINST(:word_0 IN NATURAL LANGUAGE MODE) THEN 2 ELSE 0 END) +
(CASE WHEN MATCH(cl.description) AGAINST(:word_0 IN NATURAL LANGUAGE MODE) THEN 1 ELSE 0 END) +
(CASE WHEN MATCH(cpl.description) AGAINST(:word_0 IN NATURAL LANGUAGE MODE) THEN 1 ELSE 0 END) as relevance, py.package_id as py_package_id
FROM lara237posts as a
INNER JOIN lara237categories as c ON c.id=a.category_id AND c.active=1
LEFT JOIN lara237categories as cp ON cp.id=c.parent_id AND cp.active=1
LEFT JOIN (SELECT MAX(id) max_id, post_id FROM lara237payments WHERE active=1 GROUP BY post_id) mpy ON mpy.post_id = a.id AND a.featured=1
LEFT JOIN lara237payments as py ON py.id=mpy.max_id
LEFT JOIN lara237packages as p ON p.id=py.package_id
LEFT JOIN lara237categories as cl ON cl.translation_of=c.id AND cl.translation_lang = :translationLang
LEFT JOIN lara237categories as cpl ON cpl.translation_of=cp.id AND cpl.translation_lang = :translationLang
WHERE a.country_code = :countryCode AND (a.verified_email = 1 AND a.verified_phone = 1) AND a.archived != 1 AND a.deleted_at IS NULL AND a.reviewed = 1
GROUP BY a.id, relevance
HAVING relevance >= :average
ORDER BY p.lft DESC, relevance DESC, a.created_at DESC
LIMIT 0, 16
Any help or tips will be greatly appreciated.
Thank you very much in advance
I am doing substraction from TotalAmt to NetTotal but when TotalAmt is Less than NetTotal then Due is Showing Negative values.How do i display Due as zeros if TotalAmt is Less than NetTotal.My Query for retrieving Due amount is
SELECT DISTINCT id,
name,
TotalAmt,
NetTotal,
Due
FROM
(SELECT u.id,
u.name,
(SELECT SUM(amt)
FROM pay_master
WHERE refsid = u.id
AND typ IN ('std_deposit',
'sale_ind')
GROUP BY refsid) AS 'TotalAmt',
(SELECT IFNULL(SUM(net_total), 0)
FROM trans_master t
WHERE t.refid = u.id
GROUP BY t.refid) AS 'NetTotal',
IFNULL(
(SELECT IFNULL(SUM(amt), 0)
FROM pay_master p
WHERE p.refsid = u.id
AND typ IN ('std_deposit', 'sale_ind')
GROUP BY refsid) -
( SELECT IFNULL(SUM(net_total), 0)
FROM trans_master t
WHERE t.refid = u.id
GROUP BY t.refid), 0) AS 'Due'
FROM USER u
INNER
JOIN pay_master p ON p.refsid = u.id
AND u.typ = 'std')x
Are you looking for this??
SELECT DISTINCT id,
name,
TotalAmt,
NetTotal,
case when Due < 0 then 0 else Due end
FROM
(SELECT u.id,
u.name,
(SELECT SUM( amt )
FROM pay_master
WHERE refsid = u.id
AND typ IN ( 'std_deposit', 'sale_ind')
GROUP BY refsid
) AS 'TotalAmt',
(SELECT IFNULL( SUM( net_total ) , 0 )
FROM trans_master t
WHERE t.refid = u.id
GROUP BY t.refid
) AS 'NetTotal',
IFNULL(
(SELECT IFNULL( SUM( amt ) , 0 )
FROM pay_master p
WHERE p.refsid = u.id
AND typ IN ( 'std_deposit', 'sale_ind')
GROUP BY refsid
) -
(SELECT IFNULL( SUM( net_total ) , 0 )
FROM trans_master t
WHERE t.refid = u.id
GROUP BY t.refid
) , 0) AS 'Due'
FROM USER u
INNER JOIN pay_master p
ON p.refsid = u.id
AND u.typ = 'std'
)x
Use case to maintain for such of condition
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