In MySQL, what order is the resultset if GROUP BY is used but ORDER BY is not specified?
I have inherited code with queries like:
SELECT col1, COUNT(col1)
FROM table
GROUP BY col1
(Actually the SELECT statement can be much more complex than that, involving JOINs etc., but let's start with the base principle.) Note that there is no ORDER BY.
In, say, SQL Server BOL, I am told:
The GROUP BY clause does not order the result set. Use the ORDER BY
clause to order the result set.
I have been unable to find a statement as to whether MySQL GROUP BY does or does not promise a particular ordering from GROUP BY alone? If a MySQL reference could be provided to back up any answer that would be most welcome.
From the manual:
If you use GROUP BY, output rows are sorted according to the GROUP BY
columns as if you had an ORDER BY for the same columns. To avoid the
overhead of sorting that GROUP BY produces, add ORDER BY NULL:
SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
Relying on implicit GROUP BY sorting (that is, sorting in the absence
of ASC or DESC designators) is deprecated. To produce a given sort
order, use explicit ASC or DESC designators for GROUP BY columns or
provide an ORDER BY clause.
Related
I've been told that I can't have GROUP BY and ORDER BY in one MySQL Query. Here is an abbreviated version of the query -
SELECT n.colorName, n.colorComp, n.colorID, SUM(n.gallons) AS TotalGallons
FROM netTran n, Store m, Product p
WHERE ((n.store = m.store) and m.state = "FL")
AND ((n.salesNbr = p.salesNbr) AND (p.intExt = "EXTERIOR" OR p.intExt = "INT/EXT"))
AND ((n.clrnt1 = "L1") AND (n.clrnt1 = "R3"))
GROUP BY n.colorComp, n.colorID
ORDER BY TotalGallons DESC;
I've been told that having the ORDER BY with the GROUP BY will give me different results and that the only way the ORDER BY would work is if the main query were nested in
SELECT * FROM
(query)
ORDER BY TotalGallons DESC;
Is that correct?
Use the query as
SELECT n.colorName, n.colorComp, n.colorID, SUM(n.gallons) AS TotalGallons
FROM netTran n, Store m, Product p
WHERE ((n.store = m.store) and m.state = "FL")
AND ((n.salesNbr = p.salesNbr) AND (p.intExt = "EXTERIOR" OR p.intExt = "INT/EXT"))
AND ((n.clrnt1 = "L1") AND (n.clrnt1 = "R3"))
GROUP BY n.colorName, n.colorComp,n.colorID
ORDER BY TotalGallons DESC;
You can have grouo by and order by in a single query. But you need to provide all columns in case of you are aggregating a column
Group by will change the results.. Order by will just present data in order..
Having the ORDER BY with the GROUP BY won't give you different results
Yes, that's true. In the mysql reference manual you can read th
If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL:
I suppose that this means that ORDER BY has no effect at all.
Curious... I always thought that order by worked...
GROUP BY and ORDER BY are two different things. It is plain wrong that you cannot use them together.
GROUP BY is used to tell the DBMS per which group to aggregate the data. In your example you sum gallons per colorComp and colorID.
ORDER BY is used to tell the DBMS in which order you want the data shown. In your query by the sum of gallons descending.
In standard SQL you don't usually use GROUP BY without ORDER BY, because in spite of the grouping, the data may be shown unordered. MySQL however decided to guarantee that GROUP BY performs an ORDER BY. So in MySQL it was not necessary to use ORDER BY after GROUP BY, as long as you didn't want another order as in your example. This non-standard behavior is now deprecated. See here:
https://dev.mysql.com/doc/refman/5.6/en/group-by-optimization.html
However, relying on implicit GROUP BY sorting is deprecated.
So you should have an ORDER BY clause now whenever you want data sorted. With no exception.
I ran the following query by accident and it works, and now im' confused as to why it works. Can someone please explain how to interpret this query...
(select name from employe_info limit 100) order by name;
I always assumed the 'order by' has to be associate with an explicit select clause, but in this case it's outside the () and it works. This is probably not a good form, but i just want to know if this works by accident or is this expected?
Thanks!
You just apply sorting to subquery
See more in manual: https://dev.mysql.com/doc/refman/5.5/en/select.html
If ORDER BY occurs within a subquery and also is applied in the outer
query, the outermost ORDER BY takes precedence. For example, results
for the following statement are sorted in descending order, not
ascending order:
(SELECT ... ORDER BY a) ORDER BY a DESC;
Looks like that is only a partial query.
From UNION Syntax:
To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT
and a paragraph later:
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one.
Okay, here is my query:
SELECT NAME,
DATE_FORMAT(DATE_WRITTEN, "%c/%e/%y") AS written_date,
DATE_FORMAT(RETURN_DATE, "%c/%e/%y") AS return_date
FROM `pfp`.`returns` AS `Re`
LEFT JOIN `pfp`.`insurance` AS `Insurance`
ON ( `insurance`.`id` = `Re`.`INSURANCE_ID` )
LEFT JOIN `pfp`.`remain` AS `Remain`
ON ( `remain`.`id` = `Re`.`REMAIN_ID` )
LEFT JOIN `pfp`.`formula` AS `Formula`
ON ( `formula`.`id` = `remain`.`FORMULA_ID` )
WHERE `NOT_RETURNED` = 'F'
AND `RETURN_DATE` BETWEEN '2014-01-01' AND '2014-08-22'
ORDER BY `RETURN_DATE` DESC
LIMIT 100
The problem is that it sorts by the date 14-8-9 down to 14-8-7 then jumps back up to 14-8-22 and downward from there... why??
When you sort by return_date, you are sorting by the formatted alias. Instead, use the table alias to identify that you really want the column:
WHERE `NOT_RETURNED` = 'F'
AND `RETURN_DATE` BETWEEN '2014-01-01' AND '2014-08-22'
ORDER BY re.RETURN_DATE DESC
LIMIT 100
I am guessing that it is in the re table. Use the appropriate alias.
EDIT:
The fact that the column aliases are searched first is documented:
MySQL resolves unqualified column or alias references in ORDER BY
clauses by searching in the select_expr values, then in the columns of
the tables in the FROM clause. For GROUP BY or HAVING clauses, it
searches the FROM clause before searching in the select_expr values.
(For GROUP BY and HAVING, this differs from the pre-MySQL 5.0 behavior
that used the same rules as for ORDER BY.)
I can speculate on the reasons for this (which I think is consistent with the ANSI standard). SQL queries are logically processed in a particular order, something like from, then where, then select, then order by (leaving out other clauses). This logical processing determines how the query is compiled and what identifiers mean. The logical processing explains why column aliases are not allowed in the where clause -- from the perspective of the compiler, they are not yet identified.
When it comes to the order by, the identifier is determined from the inside out. The first definition is the version in the select, so it chooses that before going to the from.
i'm using this query to search inside table:
SELECT
*,
MATCH(tags,title,description)
AGAINST ('hey you are you in' IN BOOLEAN MODE) AS score
FROM table
ORDER BY insert_datetime DESC, id DESC
what i need is to use the alias 'score' to order results, is this the right sintax?:
SELECT
*,
MATCH(tags,title,description)
AGAINST ('hey you are you in' IN BOOLEAN MODE) AS score
FROM table
ORDER BY score DESC, insert_datetime DESC, id DESC
is also there anyway to optimize this query ? better way to write that?
is this the right sintax?
Yes. As documented under SELECT Syntax:
A select_expr can be given an alias using AS alias_name. The alias is used as the expression's column name and can be used in GROUP BY, ORDER BY, or HAVING clauses.
is also there anyway to optimize this query ? better way to write that?
If you don't need the relevance score in your resultset, you need not select it:
SELECT *
FROM table
ORDER BY MATCH(tags, title, description) AGAINST (
'hey you are you in' IN BOOLEAN MODE
) DESC, insert_datetime DESC, id DESC
But sadly, as suggested under ORDER BY Optimization, there is no way that MySQL can avoid undertaking a filesort when ordering by the result of a function such as MATCH() ... AGAINST():
In some cases, MySQL can use an index to satisfy an ORDER BY clause without doing any extra sorting.
The index can also be used even if the ORDER BY does not match the index exactly, as long as all of the unused portions of the index and all the extra ORDER BY columns are constants in the WHERE clause.
However, one could:
filter the resultset for only those records of interest by using a WHERE clause, thereby reducing the number of results that must be sorted; and/or
reduce the maximum number of comparisons each sorting step will need to perform by removing unneeded columns from the ORDER BY clause.
I have query as follow
SELECT * FROM content_type_product cp
JOIN content_field_product_manufacturer cf ON cf.nid = cp.nid group by cp.nid
ORDER
BY field(cf.field_product_manufacturer_value,'12') DESC,
cp.field_product_price_value DESC
This is working perfect just a small flaw, there are two records having the same id (one is for cf.field_product_manufacturer_value='12' and other is for cf.field_product_manufacturer_value = '57') which I eliminated using group by clause. But the problem is that I want to get that particular id which has greater "field_product_price_value" but somehow it gives me the value which is lesser. If I query it for '57' then it gives me the id with greater field_product_price_value but when I query it for '12' it gives me id for lesser "field_product_price_value". Is there any way where I can specify to pick the id with greater "field_product_price_value"
You should use max(field_product_price_value) combined with appropriate GROUP BY-clause.
In general, you should use GROUP BY-clause only when you select both normal columns and aggregate functions (MIN, MAX, COUNT, AVG) in the query.
You query is using a (mis)feature of MySQL called Hidden Columns. This is only advised when all the unaggregated columns in the SELECT and not in the GROUP BY have the same value. This is not the case, so you need to select the correct records yourself:
SELECT cp.*, cf.*
FROM content_type_product cp JOIN
content_field_product_manufacturer cf
ON cf.nid = cp.nid join
(select cf.nid, max(field_product_price_value) as maxprice
from content_field_product_manufacturer
group by cf.nid
) cfmax
on cf.nid = cfmax.nid and cf.field_product_price_value = cfmax.maxprice
ORDER BY field(cf.field_product_manufacturer_value,'12') DESC,
cp.field_product_price_value DESC
Unless you really know what you are doing, when you use a GROUP BY, be sure all unaggregated columns in the SELECT are in the GROUP BY.
'2' > '12'
if we are talking about varchars. I believe you should convert your field to number type and your sort will work fine. Read this article for more information.