`ORDER BY` before `GROUP BY` in a request with INNER JOIN? - mysql

Initially I need to build a query fetching sites from one table ordered by date of newest article (articles placed in the separate table).
I build the following query:
SELECT *
FROM `sites`
INNER JOIN `articles` ON `articles`.`site_id` = `sites`.`id`
ORDER BY `articles`.`date` DESC
GROUP BY `sites`.`id`
I supposed that SELECT and INNER JOIN will fetch all posts and associate a site to each one, than ORDER BY will order the result by descending of post date than GROUP BY will take the very first post for each site and I will get the needed result.
But I'm receiving MySQL error #1064 - 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 'GROUP BYsites.idLIMIT 0, 30' at line 7
If I place GROUP BY before ORDER BY statement the query is working but it will not give me the newest post for each site. Instead the result will be sorted after the grouping which is not the thing I need (actually I could prefer to order in another way after grouping).
I read several pretty similar questions but they all related to the data stored in a single table making it possible to use MAX and MIN functions.
What should I do to implement what I need?

You can use either a subquery / derived-table / inline-view or a self-exclusion join, e.g.:
SELECT s.*, a1.*
FROM `sites` s
INNER JOIN `articles` a1 ON a1.`site_id` = s.`id`
LEFT OUTER JOIN `articles` a2 ON a2.`site_id` = a1.`site_id`
AND a2.`date` > a1.`date`
WHERE
a2.`site_id` IS NULL
ORDER BY
a1.`date` DESC
The principle is that you select the sites for which there is no article date greater than any other article date.

rewrite the sql to the following syntax -
SELECT `articles`.`article_name`,'sites'.'id','articles'.'site_id'
FROM `sites`,'articles'
WHERE `articles`.`site_id` = `sites`.`id`
ORDER BY 'sites'.'id', `articles`.`date` DESC;
Do something like this in the select statement. Group by function demands that all fields to be grouped. Hence usage of * is not possible.

SELECT * FROM ( SELECT `S.<col1>`, `S.<col2>`, `A.<col1>`,`A.<col2>`,
ROW_NUMBER ()
OVER (PARTITION BY `SITES`.`ID`
ORDER BY `SITES`.`ID` DESC)
RID
FROM `SITES` `S`,`ARTICLES` `A`
WHERE `ARTICLES`.`SITE_ID` = `SITES`.`ID`
)
WHERE RID = 1;
Can you try this?

Finally I came to the solution.
First of all I changed the main query from queering from sites table to queering from articles. Next I added the MAX(date) column to the result.
So the resulting query implementing the thing I need is the following:
SELECT `sites`.`url`,MAX(`articles`.`date`) AS `last_article_date`
FROM `articles`
INNER JOIN `sites` ON `sites`.`id` = `article`.`site_id`
GROUP BY `site_id`
ORDER BY `last_article_date` ASC
Thanks to all of you for giving me hints and right search directions!

Related

MariaDB select from inner joined query

I am not able to further select from a joined subquery.
I have data in three tables: "events", "records" and "work_list". Each table has one piece of the puzzle where work_list is the shortest and contains top-level data, and the events table tracks many tiny frequent events.
I need to calculate many statistical variables from the events based on some key variables defined in work_list like weighted moving average etc. I have those metrics ready and working, but I have problems filtering the data in events based on selected parameters stored in work_list.
Here is code that does not work. The SELECT * is not important, I will change it to be more meaningful later, it is for clarity. However, I have tried many selections in place of the * without success.
What is wrong with this query from subquery?
Query example 1:
SELECT * FROM
(SELECT events.id, events.type,events.timestamp, work_list.task
FROM
( events
INNER JOIN records ON events.record_id = records.id
INNER JOIN work_list ON records.work_list_id = work_list.id
)
WHERE work_list.customer_number = '1234' AS subquery
);
#1064 - 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 'as subquery ) LIMIT 0, 25' at line 8
The inner joined subquery works and it returns a normal table.
Query example 2:
SELECT events.id, events.type,events.timestamp, work_list.task
FROM (
events
INNER JOIN records ON events.record_id = records.id
INNER JOIN work_list ON records.work_list_id = work_list.id
)
WHERE work_list.customer_number = '1234';
I tried using parenthesis in different orders, and I changed selected variables in SELECT events.id, events.type,events.timestamp, work_list.task. I wonder if this is a poor way of doing this. I have the calculation part. So even if there might be better structures for this, I am interested in solutions that maintain this structure.
The goal of this phase is to filter the events table for further queries that are coded on top of it replacing the SELECT *.
These are the final calculations made earlier which I plan to use when I figure out the problem with Query example 1.
Query example 3:
SELECT *, ((SUM(rate * diff) OVER (ORDER BY startTime
ROWS BETWEEN 4 PRECEDING AND CURRENT ROW)) /
(SUM(diff) OVER(ORDER BY startTime
ROWS BETWEEN 4 PRECEDING AND CURRENT ROW))) as rate_WMA
FROM (
SELECT id, startTime, counts, diff, (counts / diff)*3600 as rate
FROM (
SELECT id, TIMESTAMPDIFF(SECOND, MIN(timestamp), MAX(timestamp))AS diff, SUM(change) as counts, MIN(timestamp) as startTime
FROM `the filered subquery here`
GROUP BY id
) AS subquery
WHERE diff > 0
) AS totaltotal;
You have extra parenthesis (no need for those) and the alias for the subquery should be placed after the subquery:
SELECT *
FROM (
SELECT events.id, events.type,events.timestamp, work_list.task
FROM events
INNER JOIN records ON events.record_id = records.id
INNER JOIN work_list ON records.work_list_id = work_list.id
WHERE work_list.customer_number = '1234'
) AS subquery;

MySQL Workbench, how to fix "SELECT is not valid at this position for this server version" error

As the title says, the MySQL Workbench is reporting an error. The error is from the software, not from MySQL, as far as I can tell. However, it's preventing me from bug fixing the code, as it will not work on my website.
Originally I used this query, which works perfectly fine, but is very slow, as it has a select inside the inner join.
SELECT *
FROM modeller AS m
INNER JOIN
bilder AS b ON b.ID = (
SELECT ID FROM bilder AS b2
WHERE b2.modellID = m.id
ORDER BY filnavn
DESC LIMIT 1
)
order by m.fornavn
So I've been looking around for a replacement and ended up with this:
SELECT *
FROM (
SELECT p.*,
m.*,
row_number() over (partition by m.id order by filnavn desc) rono
FROM modeller AS m
INNER JOIN bilder AS B
on B.modellID= m.ID
) x
WHERE x.rono = 1
What this query is supposed to do it to look through a database of 3D models ('modeller') and get the latest picture added to that model in the table 'bilder'. This is a one-to-many connection, bilder has modellID as a column, which corresponds to the ID in modeller.
Instead, I get the error
SELECT is not valid at this position for this server version, expecting : '(', WIDTH
Any tips hints or suggestions are greatly appreciated, especially something that not only circumvents the Workbench-error, but also improves on my initial query.
An alternative you could try is:
SELECT *
FROM modeller AS m
INNER JOIN (
SELECT model1ID, MAX(filnavn) AS filnavnMax
FROM bilder
GROUP BY model1ID
) AS maxVals
ON m.id = maxVals.model1ID
INNER JOIN bilder AS b
ON maxVals.model1ID = b.model1ID AND maxVals.filnavnMax = b.filnavn
ORDER BY m.fornavn
;
However, if filnavn is not unique for a model1ID, you could end up with more results than your original query returned. But if that is the case, your original query could provide inconsistent results (since there is no guarantee the ID returned from the original subquery would be consistent when there is more than one row with the highest filnavn)

mysql DISTINCT() does not work as expected

I want to get list of posts sorted by number of comments, I've successfully ran following query but it gives repetitive values i.e posts repeat, I want unique of them sorted by number of comments, when I put DISTINCT() around my whole query, an error appears:
#1064 - 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 'UNIQUE(post.pname, post.pid FROM post, COMMENT WHERE post.pid = comment.pid ORD' at line 1
Query without DISTINCT() (Works but of course doesn't give unique values)
SELECT post.pname, post.pid
FROM post,
COMMENT WHERE post.pid = comment.pid
ORDER BY (
SELECT COUNT( * )
FROM COMMENT WHERE comment.pid = post.pid
GROUP BY post.pname
)
Query with DISTINCT() (doesn't work)
SELECT DISTINCT(post.pname, post.pid
FROM post,
COMMENT WHERE post.pid = comment.pid
ORDER BY (
SELECT COUNT( * )
FROM COMMENT WHERE comment.pid = post.pid
GROUP BY post.pname
))
DISTINCT should be used thus:
SELECT DISTINCT a,b,c FROM t;
without a GROUP BY. It will find all the (a,b,c) in the table, then de-dup them.
This is broken:
SELECT id, a, b FROM t GROUP BY id;
That is because it will find all the distinct values of id, but supply random values of a and b to go with each.
To find out how many of each foo there are, this pattern works nicely:
SELECT foo, COUNT(*) FROM t GROUP BY foo;
Don't use () after DISTINCT.
Since I don't understand what you are looking for, I may or may not have provided you enough info to fix your query. If I have failed, please provide some sample data and the desired output; sometimes reverse engineering is the easiest way to figure it out.
SELECT distinct(post.pname) FROM post,COMMENT WHERE post.pid = comment.pid ORDER BY (SELECT COUNT( * ) FROM COMMENT WHERE comment.pid = post.pid GROUP BY post.pname) DESC
SELECT post.pname, post.pid
FROM post
Inner Join ( Select
comment.pid
, COUNT(*) As Cant
From COMMENT
Group By
comment.pid
) As x
On post.pid = x.pid
ORDER BY x.Cant
SELECT p.*
FROM post p JOIN comment c ON c.postId = p.id
GROUP BY p.id
ORDER BY COUNT(*)

Incorrect group by and order by merge

I have couple tables joined in MySQL - one has many others.
And try to select items from one, ordered by min values from another table.
Without grouping in seems to be like this:
Code:
select `catalog_products`.id
, `catalog_products`.alias
, `tmpKits`.`minPrice`
from `catalog_products`
left join `product_kits` on `product_kits`.`product_id` = `catalog_products`.`id`
left join (
SELECT MIN(new_price) AS minPrice, id FROM product_kits GROUP BY id
) AS tmpKits on `tmpKits`.`id` = `product_kits`.`id`
where `category_id` in ('62')
order by product_kits.new_price ASC
Result:
But when I add group by, I get this:
Code:
select `catalog_products`.id
, `catalog_products`.alias
, `tmpKits`.`minPrice`
from `catalog_products`
left join `product_kits` on `product_kits`.`product_id` = `catalog_products`.`id`
left join (
SELECT MIN(new_price) AS minPrice, id FROM product_kits GROUP BY id
) AS tmpKits on `tmpKits`.`id` = `product_kits`.`id`
where `category_id` in ('62')
group by `catalog_products`.`id`
order by product_kits.new_price ASC
Result:
And this is incorrect sorting!
Somehow when I group this results, I get id 280 before 281!
But I need to get:
281|1600.00
280|2340.00
So, grouping breaks existing ordering!
For one, when you apply the GROUP BY to only one column, there is no guarantee that the values in the other columns will be consistently correct. Unfortunately, MySQL allows this type of SELECT/GROUPing to happen other products don't. Two, the syntax of using an ORDER BY in a subquery while allowed in MySQL is not allowed in other database products including SQL Server. You should use a solution that will return the proper result each time it is executed.
So the query will be:
For one, when you apply the GROUP BY to only one column, there is no guarantee that the values in the other columns will be consistently correct. Unfortunately, MySQL allows this type of SELECT/GROUPing to happen other products don't. Two, the syntax of using an ORDER BY in a subquery while allowed in MySQL is not allowed in other database products including SQL Server. You should use a solution that will return the proper result each time it is executed.
So the query will be:
select CP.`id`, CP.`alias`, TK.`minPrice`
from catalog_products CP
left join `product_kits` PK on PK.`product_id` = CP.`id`
left join (
SELECT MIN(`new_price`) AS "minPrice", `id` FROM product_kits GROUP BY `id`
) AS TK on TK.`id` = PK.`id`
where CP.`category_id` IN ('62')
order by PK.`new_price` ASC
group by CP.`id`
The thing is that group by does not recognize order by in MySQL.
Actually, what I was doing is really bad practice.
In this case you should use distinct and by catalog_products.*
In my opinion, group by is really useful when you need group result of agregated functions.
Otherwise you should not use it to get unique values.

Constantly getting syntax error after subquery alias (happens with different queries)

It's probably something I can't seem to understand with MySQL, but after wasting my day going through StackOverflow's related questions without fixing the issue, I decided to ask about it.
SELECT users.idUser, users.name, categoryName
FROM users
LEFT JOIN (
SELECT `translation` as categoryName
FROM localization,
usercategories
WHERE localization.`string` = usercategories.name
AND usercategories.idUserCategory = users.idUserCategory
)
as Something
WHERE users.idUser != 1
ORDER BY users.name ASC
Whichever query I tried today that would include a subquery, I would get the same syntax error at pretty much the same place: right after the subquery's alias (in this case, Something).
#1064 - 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 'WHERE users.idUser != 1 ORDER BY users.name ASC LIMIT 0, 30' at line 11
This issue here is that you're missing the ON clause of your join. You need to select a condition to join the two tables together, like this:
SELECT stuff
FROM stuff
LEFT JOIN (other stuff)
ON stuff.something = otherstuff.something. // Add here.
You're JOIN criteria is non-ANSI and does not have an ON clause ... perhaps that is causing it? Try this, a bit more optimized:
SELECT Usr.idUser AS idUser
,Usr.name AS name
,UsrCat.translation AS categoryName
FROM users AS Usr
LEFT OUTER JOIN usercategories AS UsrCat
ON UsrCat.idUserCategory = Usr.idUserCategory
LEFT OUTER JOIN localization AS Lcl
ON Lcl.string = UsrCat.name
WHERE Usr.idUser <> 1
ORDER BY Usr.name ASC
No need for subquery, should be pretty performant.
You could re-organize your query so that it does not need a sub-query. This would also allow you the benefit of adding more columns to the select from any of the tables. Also, it is more correct.
SELECT
users.idUser,
users.name,
localization.`translation` as categoryName
FROM users
LEFT JOIN usercategories ON usercategories.idUserCategory = users.idUserCategory
LEFT JOIN localization ON localization.`string`= usercategories.name
WHERE users.idUser <> 1
ORDER BY users.name ASC