SqlAlchemy: how to select in another select like this? - sqlalchemy

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...

Related

MySQL Query Help: Giving Two Different Results

My Sample Data: http://sqlfiddle.com/#!9/e29e54/7
My goal is to find a COUNT and SUM of sold items as well as quoted items.
SELECT
clients.`id`,
COUNT(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_count,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_client,
COUNT(clients.`id`) AS quote_count,
SUM(clients.`premium`) AS quote_client,
users.last_name, users.first_name
FROM `clients`
LEFT JOIN `users` ON `clients`.`user_id` = `users`.`id`
WHERE clients.`policy_date` IN (
SELECT policy_date FROM clients WHERE month(`policy_date`) = '2' AND year(`policy_date`) = '2018'
)
GROUP BY `users`.`last_name`
ORDER BY users.`id` ASC;
Both sold_count and quote_count return the same number, 3, as if "clients.paid_to_date != clients.policy_date" is not working. It should return 2 results for user_id = 1, John Smith.
This query returns 1 results for user:
SELECT id, client_number, policy_number, agent_name, paid_to_date, policy_date
FROM `clients` WHERE `user_id` = '1' AND month(`policy_date`) = '2'
AND year(`policy_date`) = '2018'
AND `paid_to_date` != `policy_date`
ORDER BY `policy_date` ASC
Any advise on how to get the sold_count and sold_clients IF statement to work correctly would be greatly appreciated!!
I would of thought for the first query
Sold Count = 2, instead of 3.
The sold_client is correctly adding the 2 results but the count is not correct.
Basher
So simple.. what was I thinking. here's my solution:
SELECT clients.id,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, 1, 0)) AS sold_count,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_client,
COUNT(clients.`id`) AS quote_count,
SUM(clients.`premium`) AS quote_client, users.last_name, users.first_name
FROM `clients`
LEFT JOIN `users` ON `clients`.`user_id` = `users`.`id`
WHERE clients.`policy_date` IN (
SELECT policy_date FROM clients WHERE month(`policy_date`) = '2' AND year(`policy_date`) = '2018'
)
GROUP BY users.`last_name`
ORDER BY users.`id` ASC;
Changed first SUM() to just sum the result count.

mysql : query three times on the same table

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

SQL simplication

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`

how do I change my complex mysql query into mysql view

I'm a nubie in mysql queries, and I would like to ask, whether if there's someone who can help me to solve my problem. I have this complex(for me) sql. and I want to change it into a view.
SELECT
username,
user_id,
sum(result_points) AS count_points,
count(result_points) AS activity_done,
(
(
SELECT count(*) FROM `activity` WHERE periode_id = ''
) +
(
SELECT
IFNULL(sum(acs.result_points), 0)
FROM
user_activity ua
WHERE
periode_id = ''
AND ua.user_id = user_activity.user_id
AND ua.result_points IS NOT NULL
)
) AS total
FROM
user_activity
LEFT JOIN users ON users.id = user_activity.user_id
WHERE
periode_id = ''
and user_id > 0
GROUP BY user_id
ORDER BY total DESC
is there a way, to take out the "where" statement,so that i still can change it to view?
If you query is correct, create view like
Create View data as
SELECT
username,
user_id,
sum(result_points) AS count_points,
count(result_points) AS activity_done,
(
(
SELECT count(*) FROM `activity` WHERE periode_id = ''
) +
(
SELECT
IFNULL(sum(acs.result_points), 0)
FROM
user_activity ua
WHERE
periode_id = ''
AND ua.user_id = user_activity.user_id
AND ua.result_points IS NOT NULL
)
) AS total
FROM
user_activity
LEFT JOIN users ON users.id = user_activity.user_id
WHERE
periode_id = ''
and user_id > 0
GROUP BY user_id
ORDER BY total DESC
Remove where clause from view and add where clause in view, like
select * from data where user_id > 0

Set limit for MySQL query

I have query like this:
SELECT `all_messages`.`user_1`, `messages`.*, `users`.`username`
FROM `all_messages`
JOIN `messages` ON (`all_messages`.`user_2` = `messages`.`from_user`)
JOIN `users` ON (`all_messages`.`user_2` = `users`.`id`)
WHERE `all_messages`.`user_1` = '12'
ORDER BY `messages`.`sent` DESC LIMIT 2
Now this query does what I need but my problem is with this line
ON (`all_messages`.`user_2` = `messages`.`from_user`)
It selects all data from messages where the matches was found but I need only one newest record. I hope you guys get what I mean.
If you need one "newest record" you should have a date column or something, lets name it "CREATION_TIME", so you could do something like this
SELECT AM.user_1, M.*, U.username
FROM all_messages AM, messages M , users U
WHERE AM.user_1 = '12'
AND AM.user_2 = M.from_user
AND AM.user_2 = U.id
AND M.CREATION_TIME =
(
SELECT MAX(CREATION_TIME)
FROM messages
WHERE from_user= M.from_user
)
ORDER BY M.sent DESC LIMIT 2
Edit
SELECT AM.user_1, M.*, U.username
FROM all_messages AM, messages M, users U
WHERE AM.user_1 = '12'
AND AM.user_2 = M.from_user
AND AM.user_2 = U.id
AND M.sent =
(
SELECT MAX(sent)
FROM messages
WHERE from_user= M.from_user
)
ORDER BY M.sent DESC LIMIT 2
It should work