SELECT id FROM table LIMIT 8, 3
results in 8,9,10
but I need 10,9,8
How can you do this? If you add "ORDER BY id DESC" it gets 3,2,1
Put your query in a subselect and then reverse the order in the outer select:
SELECT id from (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Test data:
CREATE TABLE table1 (id INT NOT NULL);
INSERT INTO table1 (id) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
SELECT id from (
SELECT id FROM table1 ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Result:
10
9
8
Note that the ORDER BY in the subquery is required otherwise the order is undefined. Thanks to Lasse for pointing this out!
First of all, if you're not ordering at all, that you got 8,9,10 right now might be related to the index used. Are you sure this isn't going to change in the future?
What I'm getting at is that unless you specify an order, you should not rely on it being the one you want.
So I would definitely add an order to that select to specify what you want. Otherwise you're only saying "give me 3 numbers from this table", not "give me 3 numbers from this table according to these rules". Why is 3,2,1 wrong but 8,9,10 right? You're not specifying.
Anyway, to answer your question, you must order after the limit, which means a subselect:
SELECT id FROM (
SELECT id FROM table LIMIT 8, 3
) AS dummy ORDER BY id DESC
However, I would try this SQL instead, related to the part about specifying:
SELECT id FROM (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS dummy ORDER BY id DESC
Related
I want to use ORDER BY on every UNION ALL queries, but I can't figure out the right syntax. This is what I want:
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123 AND user_in IN (...)
ORDER BY name
)
UNION ALL
(
SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456 AND user_id NOT IN (...)
ORDER BY name
)
EDIT:
Just to be clear: I need two ordered lists like this, not one:
1
2
3
1
2
3
4
5
Thank you very much!
Something like this should work in MySQL:
SELECT a.*
FROM (
SELECT ... FROM ... ORDER BY ...
) a
UNION ALL
SELECT b.*
FROM (
SELECT ... FROM ... ORDER BY ...
) b
to return rows in an order we'd like them returned. i.e. MySQL seems to honor the ORDER BY clauses inside the inline views.
But, without an ORDER BY clause on the outermost query, the order that the rows are returned is not guaranteed.
If we need the rows returned in a particular sequence, we can include an ORDER BY on the outermost query. In a lot of use cases, we can just use an ORDER BY on the outermost query to satisfy the results.
But when we have a use case where we need all the rows from the first query returned before all the rows from the second query, one option is to include an extra discriminator column in each of the queries. For example, add ,'a' AS src in the first query, ,'b' AS src to the second query.
Then the outermost query could include ORDER BY src, name, to guarantee the sequence of the results.
FOLLOWUP
In your original query, the ORDER BY in your queries is discarded by the optimizer; since there is no ORDER BY applied to the outer query, MySQL is free to return the rows in whatever order it wants.
The "trick" in query in my answer (above) is dependent on behavior that may be specific to some versions of MySQL.
Test case:
populate tables
CREATE TABLE foo2 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
CREATE TABLE foo3 (id INT PRIMARY KEY, role VARCHAR(20)) ENGINE=InnoDB;
INSERT INTO foo2 (id, role) VALUES
(1,'sam'),(2,'frodo'),(3,'aragorn'),(4,'pippin'),(5,'gandalf');
INSERT INTO foo3 (id, role) VALUES
(1,'gimli'),(2,'boromir'),(3,'elron'),(4,'merry'),(5,'legolas');
query
SELECT a.*
FROM ( SELECT s.id, s.role
FROM foo2 s
ORDER BY s.role
) a
UNION ALL
SELECT b.*
FROM ( SELECT t.id, t.role
FROM foo3 t
ORDER BY t.role
) b
resultset returned
id role
------ ---------
3 aragorn
2 frodo
5 gandalf
4 pippin
1 sam
2 boromir
3 elron
1 gimli
5 legolas
4 merry
The rows from foo2 are returned "in order", followed by the rows from foo3, again, "in order".
Note (again) that this behavior is NOT guaranteed. (The behavior we observer is a side effect of how MySQL processes inline views (derived tables). This behavior may be different in versions after 5.5.)
If you need the rows returned in a particular order, then specify an ORDER BY clause for the outermost query. And that ordering will apply to the entire resultset.
As I mentioned earlier, if I needed the rows from the first query first, followed by the second query, I would include a "discriminator" column in each query, and then include the "discriminator" column in the ORDER BY clause. I would also do away with the inline views, and do something like this:
SELECT s.id, s.role, 's' AS src
FROM foo2 s
UNION ALL
SELECT t.id, t.role, 't' AS src
FROM foo3 t
ORDER BY src, role
Don't use ORDER BY in an individual SELECT statement inside a UNION, unless you're using LIMIT with it.
The MySQL docs on UNION explain why (emphasis mine):
To apply ORDER BY or LIMIT to an individual SELECT, place the clause
inside the parentheses that enclose the SELECT:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
However, use of ORDER BY for individual SELECT statements implies
nothing about the order in which the rows appear in the final result
because UNION by default produces an unordered set of rows. Therefore,
the use of ORDER BY in this context is typically in conjunction with
LIMIT, so that it is used to determine the subset of the selected rows
to retrieve for the SELECT, even though it does not necessarily affect
the order of those rows in the final UNION result. If ORDER BY appears
without LIMIT in a SELECT, it is optimized away because it will have
no effect anyway.
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. The following example uses both
clauses:
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
It seems like an ORDER BY clause like the following will get you what you want:
ORDER BY user_id, name
You just use one ORDER BY at the very end.
The Union turns two selects into one logical select. The order-by applies to the entire set, not to each part.
Don't use any parens either. Just:
SELECT 1 as Origin, blah blah FROM foo WHERE x
UNION ALL
SELECT 2 as Origin, blah blah FROM foo WHERE y
ORDER BY Origin, z
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 123
AND user_in IN (...))
UNION ALL
(SELECT id, user_id, other_id, name
FROM tablename
WHERE user_id = 456
AND user_id NOT IN (...)))
ORDER BY name
You can also simplify this query:
SELECT id, user_id, other_id, name
FROM tablename
WHERE (user_id = 123 AND user_in IN (...))
OR (user_id = 456 AND user_id NOT IN (...))
I have a database with one table called "user" having two fields:
"id" (type: INTEGER, PRIMARY KEY)
"name" (type: VARCHAR(32))
I want to Write a standard SQL query which retrieves the second highest value of "id" from the "user" table. The value returned should be represented using the column name "id".
I have tried this but it gives me all ids:
SELECT `user`.`id`
FROM `user`
ORDER BY `user`.`id` ASC
LIMIT 0 , 30
some example data in my table:
id name
----------------
1 john
2 david
3 mike
I want to get '2' but now i'm getting :
id
----
1
2
3
I can do it with help of PHP but I want to know the way with mysql (SQL).
thanks
SELECT id
FROM `user`
ORDER BY id DESC -- start with highest
LIMIT 1 -- show only 1 row
OFFSET 1 ; -- but skip the first (skip 1 row)
SELECT id FROM user ORDER BY id ASC LIMIT 1, 1
select max(id) from user where id < (select max(id) from user);
select max(id) from user where id not in (Select max(id) from user);
SELECT id
FROM `user`
ORDER BY id ASC
LIMIT 1, 1
Using limit you can set an offset and the number of records you like being returned.
How 'bout
Select max(id) from user
where id <> (select max(id) from user)
This may work:
select max(id)-1 from user;
My table has a TIME field.
I want to keep only 5 newest rows.
Can I delete the old rows without using SELECT?
I think logic should be something like this:
DELETE FROM tbl WHERE row_num > 5 ORDER BY TIME
How can I implement this in MySQL whitout using SELECT to get list of TIME values?
Without proper ORDER BY clause, SQL result set have to be considered as unordered.
You have to provide a column to explicitly store your rows sequence numbers. This could be a time stamp or the auto_increment column of your table.
Please keep in mind you could have concurrent access to your table as well. What should be the expected behavior if someone else is inserting while you are deleting? As far as I can tell this could lead to situation where you keep only the "5 latest rows" + "those inserted on the other transaction".
If your have the time column for that purpose on your table and a PRIMARY KEY (or some other UNIQUE NOT NULL column) you could write:
DELETE tbl FROM tbl LEFT JOIN (SELECT * FROM tbl ORDER BY tm DESC LIMIT 5) AS k
ON (tbl.pk) = (k.pk)
WHERE k.`time` IS NULL;
If you have composite primary key (a,b) You could write:
DELETE tbl FROM tbl LEFT JOIN (SELECT * FROM tbl ORDER BY tm DESC LIMIT 5) AS k
ON (tbl.a,tbl.b) = (k.a,k.b)
WHERE k.tm IS NULL;
DELETE FROM TBL
WHERE ROW_NUM = (SELECT ROW_NUM FROM TBL LIMIT 6, 99999)
ORDER BY TIME DESC;
This will delete records from 6, 7, 8, 9, 10, ....., 200005
Because LIMIT range starts here from 6 to 9999 records, means 200005
Maybe this would be an alternative:
DELETE FROM tbl
WHERE primary_key NOT IN (SELECT primary_key
FROM tbl
ORDER BY time
DESC LIMIT 5)
If you want to exclude the top 5 rows, use something like:
DELETE FROM table WHERE primary_key IN
(SELECT primary_key FROM table LIMIT 1 OFFSET 5,1000000)
100000 can be a very large no
I've 2 tables:
create table advertised_products(id int,title varchar(99),timestamp timestamp);
insert advertised_products select 1,'t1',curdate();
create table wanted_products(id int,title varchar(99),timestamp timestamp);
insert wanted_products select 1,'t1',now();
I'm using this query to get the records:
(
SELECT
ap.*,
'advertised' as type
FROM advertised_products as ap
)
union all
(
SELECT
wp.*,
'wanted' as type
FROM wanted_products as wp
)
ORDER BY timestamp desc limit 3
But it gives error:
Column 'timestamp' in order clause is ambiguous
How can i sort this?
Wrap it in a subquery.
SELECT s.*
FROM
(
SELECT ap.*, 'advertised' as type
FROM advertised_products as ap
union all
SELECT wp.*, 'wanted' as type
FROM wanted_products as wp
) s
ORDER BY s.timestamp desc
limit 3
Error lies in here,
"ORDER BY timestamp desc limit 3"
as you are combining the two tables query must know which fields are you using in which table.clearly that you are missing the table reference in your "orderby" clause
mention the table name/alias of the table name like below
"ORDER BY your_table_name.timestamp desc limit 3"
I have a table and I only display the latest 30 rows by order by ID.
I'm trying to delete any rows after the 30 newest rows by using this query below.
DELETE FROM table WHERE type = 'test' ORDER BY id DESC LIMIT 30, 60
I keep getting this error below
#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 ' 60' at line 1
What am I doing wrong?
Try this one,
DELETE FROM table
WHERE ID IN
(
SELECT ID
FROM
(
SELECT ID
FROM table
WHERE Type = 'TEST'
ORDER BY ID
LIMIT 30,60
) a
)
Second edit: While MySQL supports LIMIT in delete statements, it does not allow an OFFSET. This means that you cannot skip the first 30 rows.
Make a subselect on id (or any other primary key):
DELETE FROM table WHERE id IN (SELECT id FROM table WHERE type = 'test' ORDER BY id DESC LIMIT 30, 60)
This is not possible this way.
You could try it with a nested select statement, somewhat like this:
DELETE FROM table
WHERE type = 'test'
AND ID IN (SELECT id from table where type = 'test' order by id desc limit 30 )
Try like this
DELETE FROM table WHERE id in(SELECT id FROM table WHERE type = "test" order by id desc limit 30, 60)
I was unable to use the limit clause in the sub-query, so the solution I use, somewhat messy, is:-
select group_concat(id) into #idList from
(
select id from table order by id desc limit 0,30
) as saveIds;
delete from table where not find_in_set(id,#idList)
Alternatively,
select group_concat(id) into #idList from
(
select id from table order by id desc limit 30
) as saveIds;
delete from table where find_in_set(id,#idList)