Here is my DB data's sample:
both two columns are int
tuanId ,tuanSort
'375579', '55'
'370576', '54'
'366222', '54'
...
'346268', '52'
'369608', '52'
'370587', '52'
'370775', '52'
...
'370225', '52'
'370588', '52'
'360758', '52'
'366390', '51'
and I try these sqls bellow:
SELECT * FROM `tuan`.`TuanItem` WHERE ... ORDER BY `tuanSort` DESC LIMIT 140,20;
SELECT * FROM `tuan`.`TuanItem` WHERE ... ORDER BY `tuanSort` DESC LIMIT 160,20;
and I get these wrong data, I want to make a pagination, but the second page has some same data in the first page:
For Example, the first pic's 17th row has shown twice in the 2 pics
So, is the sort value the same can cause such a problem? Or MySQL has problem with such a select?
Given that tuanSort is not unique, the behavior is within the specification.
You are observing that one query returns a particular row as 157th row. In another query execution, it's returned as the 161st row.
To get more deterministic sequence, specify additional columns in the ORDER BY clause, e.g.
ORDER BY tuanSort DESC, tuanId DESC
If the intent behind this sequence of statements is "paging", there are more efficient approaches, such as saving a unique, sequenced identifier from the "last" row of the previous page.
If tuanSort,tuanId tuple is unique...
WHERE tuanSort <= :last_tuanSort
AND ( tuanSort < :last_tuanSort OR tuanId < :last_tuanId )
AND ...
ORDER BY tuanSort DESC, tuanId DESC
LIMIT 20
If you fetch all twenty rows, save tuanSort and tuanId from that last row. On the next "page", supply those saved values in the query predicates.
But that's an answer to a question you didn't ask.
I think you need to refresh your database table.
Try this : Go ->TuanItem->Click Operations->Alter table order by-> select your tuanid and set as an ascending order.
I think your problem is, your getting same data in 2 query.
then change the limit 160,20 to
SELECT * FROM `tuan`.`TuanItem` WHERE ... ORDER BY `tuanSort` DESC LIMIT 140,0;
SELECT * FROM `tuan`.`TuanItem` WHERE ... ORDER BY `tuanSort` DESC LIMIT 160,141;
the 0 is the offset which means the data start at 0 and the second query start at the 141 so that you cannot get same value twice
Related
I want to improve my current query. So I have this table called Incomes. Where I have a sourceId varchar field. I have a single SELECT for the fields I need, but I needed to add an extra field called isFirstTime to represent if it was the first time on the row on what that sourceId was used. This is my current query:
SELECT DISTINCT
`income`.*,
CASE WHEN (
SELECT
`income2`.id
FROM
`income` as `income2`
WHERE
`income2`."sourceId" = `income`."sourceId"
ORDER BY
`income2`.created asc
LIMIT 1
) = `income`.id THEN true ELSE false END
as isFirstIncome
FROM
`income` as `income`
WHERE `income`.incomeType IN ('passive', 'active') AND `income`.status = 'paid'
ORDER BY `income`.created desc
LIMIT 50
The query works but slows down if I keep increasing the LIMIT or OFFSET. Any suggestions?
UPDATE 1:
Added WHERE statements used on the original query
UPDATE 2:
MYSQL version 5.7.22
You can achieve it using Ordered Analytical Function.
You can use ROW_NUMBER or RANK to get the desired result.
Below query will give the desired output.
SELECT *,
CASE
WHEN Row_number()
OVER(
PARTITION BY sourceid
ORDER BY created ASC) = 1 THEN true
ELSE false
END AS isFirstIncome
FROM income
WHERE incomeType IN ('passive', 'active') AND status = 'paid'
ORDER BY created desc
DB Fiddle: See the result here
My first thought is that isFirstIncome should be an extra column in the table. It should be populated as the data is inserted.
If you don't like that, let's try to optimize the query...
Let's avoid doing the subquery more than 50 times. This requires turning the query inside-out. (It's like "explode-implode", where the query gathers lots of stuff, then sorts it and throws most of the rows away.)
To summarize:
do the least amount of effort to just identify the 5 rows.
JOIN to whatever tables are needed (including itself if appropriate); this is to get any other columns desired (including isFirstIncome).
SELECT i3.*,
( ... using i3 ... ) as isFirstIncome
FROM (
SELECT i1.id, i1.sourceId
FROM `income` AS i1
WHERE i1.incomeType IN ('passive', 'active')
AND i1.status = 'paid'
ORDER BY i1.created DESC
LIMIT 50
) AS i2
JOIN income AS i3 USING(id)
ORDER BY i2.created DESC -- yes, repeated
(I left out the computation of isFirstIncome; it is discussed in other Answers. But note that it will be executed at most 50 times.)
(The aliases -- i1, i2, i3 -- are numbered in the order they will be "used"; this is to assist in following the SQL.)
To assist in performance, add
INDEX(status, incomeType, created, id, sourceId)
It should help with my formulation, but probably not for the other versions. Your version would benefit from
INDEX(sourceId, created, id)
I have a "reply" table with structure.
replyno topicno replydesc replyrank
Now i need to retrieve top 2 records ordered by replyrank in descending order (means first 2 high ranked records) for each topicno (which is a foreign key).
I need a query in mysql that can extract result set like this for all topic numbers.
please give me optimized query that can execute faster
Try this:
SELECT replyno, topicno, replydesc, replyrank
FROM (SELECT replyno, topicno, replydesc, replyrank,
IF(#topicno = #topicno:=topicno, #id:=#id+1, #id:=1) AS id
FROM reply, (SELECT #id:=1, #topicno:=0) A
ORDER BY topicno, replyrank DESC
) AS A
WHERE id <= 2;
Try this Query i think it gonna work for you
SELECT replyno, topicno FROM reply ORDER BY replyrank DESC LIMIT 2
I'm using this query to select a set of records from a MySQL database:
SELECT *
FROM table
WHERE id IN(10,14,12,11,8,7,4)
AND actief='on'
ORDER BY FIELD(id,10,14,12,11,8,7,4)
This will give me the given ID's. In this case I will get a maximum of 7 records. But it can be less if for example ID '14' has active='off'.
But what I need is a set of 20 records where het list IN(10,14,12,11,8,7,4) must be in the result if they also meet the condition active='on'. If this returns 6 records, then I want the query to select another 14 records. Selecting highest ID first, must meet active='on' and may not already be in the result.
Can this be achieved by one SQL statement. Or should I first put the result of the mentionend query in an array and in a second array select the remaining records. And finaly put those also in the array?
You want to sort rather than filter the results. I think this is the query you want:
SELECT *
FROM table
ORDER BY (id IN(10,14,12,11,8,7,4) AND actief = 'on') desc,
FIELD(id,10,14,12,11,8,7,4),
id desc
LIMIT 20;
EDIT:
The final solution only wanted actief = 'on', so:
SELECT *
FROM table
WHERE actief = 'on'
ORDER BY (id IN (10,14,12,11,8,7,4)) desc,
FIELD(id,10,14,12,11,8,7,4),
id desc
LIMIT 20;
Why would only one of these queries work?
Works:
SELECT *
FROM `global_rank`
WHERE rank_type = 2
AND rank < 1531.26367188
AND id <> 103
ORDER BY rank ASC
Fails (ie returns 0 rows):
SELECT *
FROM `global_rank`
WHERE rank_type = 2
AND rank < 1531.26367188
AND id <> 103
ORDER BY rank DESC
There is no problem with your sql queries they are flawless.
Please check the way you are validating your query results. I know sometimes we overlook the results ( common human error).
After pondering this for a few hours, I'm almost sure it has to be a corrupted index problem. Drop the index on rank and re-add it to see if the behavior changes.
I know there are simmilar questions out there, but here`s my implementation on a fast random select row:
SELECT i.id, i.thumb_img, i.af, i.width, i.height
FROM images_detail id
JOIN images AS i ON id.imageid = i.id
WHERE id.imageid >=1
AND id.newsroom =1
AND i.width > i.height
AND id.imageid >= FLOOR( 1 + RAND( ) *23111593 )
LIMIT 1
The problem with this query is that indifferent of the RANDOM expression in id.imageid >= FLOOR( 1 + RAND( ) *23111593 ) it always returns the same ID, why?
Any help please?
Later edit:
The query takes 0.0005 seconds, using EXPLAIN, it reports back USING WHERE and 12993 ROWS returned
The Id's are auto-incremented, it's not 23111593 because RAND() returns 0.xxxxx so RAND()*23111593, returns about 12993 rows. The problem is, the same ID is at the top and I don`t want to call an ORDER BY clause.
http://www.greggdev.com/web/articles.php?id=6
or use
ORDER BY RAND() LIMIT 0,1;
Do you have any "imageid" in your database that is greater than the span you define (1<=X<=23111593)?
You might have only one entry in the DB.
(also, keep in mind that you might only have one that actually fits the query of id.newsroom = 1, i.width>i.height etc.)
Eventually I've loaded ALL the results in an array, stored it in a cache and made in PHP $key=rand(0,sizeof(array)) and then used it as follows array[$key]['property']