Equivalent to Max() in join query WHERE - mysql

I want to be able to write ORDER BY revision_id DESC LIMIT 1 similar to Having Max(revision_id), though that does not behave as I want putting it near the WHERE clause. Putting Max(revision_id) in the select, returns the highest value of the revision ID, but the rest of the fields are not the ones that ought to go with it (it's a in a join).
Query:
SELECT * FROM field_data_field_city
LEFT JOIN profile on(field_data_field_city.entity_id = profile.pid)
LEFT JOIN users on(profile.uid = users.uid)
WHERE users.uid = 1
ORDER BY revision_id DESC
LIMIT 1`
Want to get rid of the limit so I can do it for multiple users at once
I tried with
GROUP BY users.uid
ORDER BY revision_id DESC
But I get the lowest revision_id and I want the highest

You could try below:
WHERE revision_id=(SELECT MAX(revision_id) FROM table)

Assuming the field revision_id is in your table profile you can use:
SELECT *
FROM field_data_field_city
LEFT JOIN profile ON field_data_field_city.entity_id = profile.pid
LEFT JOIN users ON profile.uid = users.uid
WHERE profile.revision_id IN (
SELECT MAX(p.revision_id)
FROM profile p
GROUP BY p.uid) T;

Related

Filter inner query by the results of the outer query

Let me start in plain english first
Query: Get top 100 paying users and their current active item (just one item)
Here is a drafted query
SELECT `user_id`, SUM(p.`amount`) as `total`
FROM `users_purcahse` AS p
LEFT JOIN (SELECT `ui`.`item_id` as `item_id`, `ui`.`user_id` as `user_id`
FROM `user_items` AS `ui`
LEFT OUTER JOIN `items` AS `i` ON `ui`.`item_id` = `i`.`id`
LEFT OUTER JOIN `categories` AS `cat` ON `i`.`category_id` = `cat`.`id`
WHERE `ui`.isActive = 1
) AS `ui` ON p.`user_id` = `ui`.`user_id`
GROUP BY `user_id`, `ui`.`item_id`
ORDER BY `total` DESC
LIMIT 0, 100;
The problem with this is that the inner query is getting all users items table and then it will join it with the top 100 paying users
user items is a very large table, the query is taking too long
I simply want to attach the current active items for each user after doing the calculations
Note: a user can have so many items but only 1 active item
Note2: it's not enforced on the DB level that user_items can have one column with is_active per user
This is a job for some well-chosen subqueries.
First, let's find the user_id values of your top-paying users.
SELECT user_id, SUM(amount) total
FROM users_purcahse
ORDER BY SUM(amount) DESC
LIMIT 100
Next, let's find the item_id values for your users. If more than one item is active, we'll take the one with the smallest item_id value to get just one.
SELECT user_id, MIN(item_id) item_id
FROM user_items
WHERE isActive = 1
GROUP BY user_id
Then, in an outer query we can fetch the details of your items.
SELECT top_users.user_id, top_users.total,
active_items.item_id,
items.*, categories.*
FROM (
SELECT user_id, SUM(amount) total
FROM users_purcahse
ORDER BY SUM(amount) DESC
LIMIT 100
) top_users
LEFT JOIN (
SELECT user_id, MIN(item_id) item_id
FROM user_items
WHERE isActive = 1
GROUP BY user_id
) active_items ON top_users.user_id = active_items.user_id
LEFT JOIN items ON active_items.item_id = item.id
LEFT JOIN categories ON item.category_id = categories.id
ORDER BY top_users.total DESC, top_users.user_id
The trick here is to use GROUP BY subqueries to get the data items where you need just one value per user_id.
Once you have the resultset you need, you can use EXPLAIN to help you sort out any performance problems.

How do I keep the order of my inner join in SQL?

I have the following command:
SELECT * FROM Posts P
INNER JOIN (SELECT DISTINCT ThreadId FROM Posts ORDER BY Time DESC) R
ON P.Id = R.ThreadId;
This command selects threads who contain the newest replies. Unfortunately the order of the threads seems to be random. I want the threads to be ordered by the newest replies. In other words: I want my selection to keep the order which I used inside my inner join.
How can I achieve this?
For MySql 8.0+ you can use MAX() window function in the ORDER BY clause:
SELECT *
FROM Posts
ORDER BY MAX(Time) OVER (PARTITION BY ThreadId)
For prior versions use a correlated subquery:
SELECT p1.*
FROM Posts p1
ORDER BY (SELECT MAX(p2.Time) FROM Posts p2 WHERE p2.ThreadId = p1.ThreadId)
You may also want to add as a 2nd argument in the ORDER BY clause , Time DESC.
Your join needs to group and select the last post per thread. The order needs to go on the outside query (not the subquery).
SELECT *
FROM Threads AS t
LEFT JOIN (
SELECT ThreadId, MAX(Time) AS LastPost
FROM Posts
GROUP BY ThreadId
) AS r ON r.ThreadId = t.ThreadId
ORDER BY LastPost DESC
You can use INNER JOIN instead of LEFT JOIN if you want to exclude threads that have no posts (if that is even possible).
you could change the order of your query like this
SELECT ...
FROM BrandsProducts
INNER JOIN Brands ON BrandsProducts.brandid = BrandsProducts.brandid
WHERE ...
ORDER BY ...

return all users posts ASC excepts last 7 ones left join sql

I want to return all my users posts except the last 7 ones. MySql.
The pattern would be something like this:
SELECT *
FROM posts
WHERE id_post < (SELECT * FROM posts min(id_post) WHERE id_user=4
ORDER BY id_post DESC LIMIT 7)
ORDER id_post ASC
If I Left Join with the Users table
SELECT q.*,q.id_post as id
FROM posts q
LEFT JOIN users u ON u.id_user=q.id_user
WHERE p.id_user=4
AND q.id_post < (SELECT min(rel.id_post) as min_id_post
FROM
(
SELECT p.*
FROM posts p
WHERE p.id_user=4
ORDER BY p.date DESC
LIMIT 7
) rel )
I retrieve the results by this last query, but it has so many subqueries...
Is it a subquery needed to achive what I want? Is there a shorter version?
You don't need an Outer Join (in fact the WHERE p.id_user=4 turns it into an Inner Join anyway).
You should be able to use a LIMIT to skip the first 7 rows:
SELECT q.*,q.id_post as id
FROM
( SELECT
FROM posts AS p
WHERE p.id_user=4
ORDER BY p.date DESC
LIMIT 8, 999999999
) q
JOIN users u ON u.id_user=q.id_user
WHERE u.id_user=4
ORDER id_post ASC
And your current query doesn't need to join to users, you don't access any column from that table (but this was probably a stripped down version)

Order rows by amount of columns in another table

I'm currently outputting all of my members by adding the MySQL clause ORDER BY id DESC, but I feel that doesn't reward people that are active on my service.
I thought about judging the order by the amount of entries in another table they have under their ID.
Essentially, I'm asking if it's possible to order columns in a MAIN table counting the amount of rows where the users ID is in the column of the row.
Something pseudo to this
SELECT user_id,name,etc FROM users ORDER BY (
COUNT(SELECT FROM users_interactions WHERE user_id = user_id) *******
) ASC
In the end of the COUNT statement, the user_id = user_id was just a guess.
You are almost there - what you need to do is to put COUNT inside SELECT:
SELECT user_id,name,etc FROM users u ORDER BY (
SELECT COUNT(*)
FROM users_interactions i
WHERE i.user_id = u.user_id
) ASC
You could also do it using a JOIN, like this:
SELECT u.user_id, u.name, u.etc
FROM users u
LEFT OUTER JOIN users_interactions i ON i.user_id = u.user_id
GROUP BY u.user_id, u.name, u.etc
ORDER BY COUNT(*) ASC

Using UNION, JOIN and ORDER by to Merge 2 identical tables

I need to join 2 identical tables to display the same list sorted by id. (posts and posts2)
It happens that before only worked with 1 table, but we've been using a second table (posts2) to store the new data from a certain id.
This is the query I used when I worked with 1 table(posts) and works fine.
select posts.id_usu,posts.id_cat,posts.titulo,posts.html,posts.slug,posts.fecha,hits.id,hits.hits,usuarios.id,usuarios.usuario,posts.id
From posts
Join hits On posts.id = hits.id
Join usuarios On posts.id_usu = usuarios.id
where posts.id_cat='".$catid."' order by posts.id desc
Now I tried to apply this query to Union 2 tables, but I don't know at what point instantiate the JOINS. I tried several ways but sends MYSQL Error. The following query merge the 2 tables and order by id, but need to add the JOIN.
select * from (
SELECT posts.id,posts.id_usu,posts.id_cat,posts.titulo,posts.html,posts.slug,posts.fecha
FROM posts where id_cat='6' ORDER BY id
)X
UNION ALL
SELECT posts2.id,posts2.id_usu,posts2.id_cat,posts2.titulo,posts2.html,posts2.slug,posts2.fecha FROM posts2 where id_cat='4' ORDER BY id DESC limit 20
I need to add this at the above query
Join hits On posts.id = hits.id
Join usuarios On posts.id_usu = usuarios.id
Thanks in advance guys.
If you want the same query as your first query but this time with union of your identical table i.e post2 then you can do so
select
p.id_usu,p.id_cat,p.titulo,p.html,p.slug,p.fecha
,hits.id,hits.hits,usuarios.id,usuarios.usuario
from (
(select
id_usu,id_cat,titulo,html,slug,fecha ,id
From posts
where id_cat='".$catid."' order by id desc limit 20)
UNION ALL
(select
id_usu,id_cat,titulo,html,slug,fecha ,id
From posts2
where id_cat='".$catid."' order by id desc limit 20)
) p
Join hits On p.id = hits.id
Join usuarios On p.id_usu = usuarios.id
order by p.id desc limit 20