MYSQL LIMIT. Is it possible to skip certain rows? - mysql

Sorry if this question is confusing.
I have inherited a site that is already built, so I can't really do anything too drastic.
The MYSQL query on a certain page uses LIMIT to only show the relevant entries like this:
comtitlesub.idcts = %s LIMIT 1,3
Skipping the first record and displaying the following three records.
I have been asked to add a new record, which is fine, but this is record number 7. Records 5 and 6 are not supposed to display on this page so changing the query to:
comtitlesub.idcts = %s LIMIT 1,6
displays all 6 records as you would expect.
One confusing thing is that I have altered the ID's for each of the records so that my new one is ID 4, and yet this did not make a difference.
Is there a simple way to 'skip' the unwanted records or am I approaching this from the wrong direction?

add "order by comtitlesub.idcts" at the end of you query, but before the limit clause.
... comtitlesub.idcts = %s ORDER BY comtitlesub.idcts LIMIT 1,6
basically, changing the id doesn't reorder them, rows are stored in order they have been created, and retrieved that way by default.

Andrew, LIMIT will delimit according to a specific order, in your case, coincidentally the default order was the same than ID order, now that you've changed it, you will need to order by ID:
ORDER BY comtitlesub.idcts

I believe the easiest course would be to modify your WHERE clause to exclude the rows you want excluded. For example:
WHERE comtitlesub.idcts = %s AND someothercol NOT IN ('cat','frog','kazoo')
Ideally for maintainability, you would want someothercol to hold stable data rather than a numeric ID which might change as your application data changes.

Related

Does pymysql's lastrowid function work properly in cases of multiple users inserting into DB?

I have 2 tables in my DB purchase order and lines. Every order can have multiple lines(one line for each part ordered). I am developing an application where an order will first be created. Need to get the ID of this order and then insert lines later on(as the user adds the parts). How can I ensure ther correct value of order ID is fetched?
I cant understand what you exactly want but you should search about ORM its maybe can help you.

SQL: paging without repetition from an dynamic table

I have an SQL table called articles from which I load rows divided by pages. My SQL is
SELECT ...
ORDER BY $orderCol DESC
LIMIT $offset, $numPerPage
On page one the limit is 0, $numPerPage, page two it's $numPerPage, 2 * $numPerPage etc.
The problem: When a new row is inserted before page 2 is loaded, the last article from page 1 will be the first article in page 2 etc. How can I avoid this?
I thought about adding a WHERE clause to select articles starting from the last $orderCol, but this field is not unique (it's a date in my case) so I'll miss articles with the same value here. The primary index is also a problem because it's not ordered the same way as $orderCol
It's not necessary that the newly added row will appear at any point. This will require a refresh.
Your LIMIT should be something like below rather. Define a $page variable which will change from 1 .. no.of pages you want.
LIMIT $offset, $page * $numPerPage
OK, in that case you will have to re-calculate your $pages and $numPerPage variable every time (on refresh) and define the paging accordingly.
The solution I found is to add a condition in the WHERE clause.
Rahul suggested that I should count the new articles since the previous query and add it to the offset. This was tricky because since counting the articles would imply that I can run a query that stops where the previous one began, and if I had a way to do that, I could've just as easily make the second query start where the first ended.
So I realized I needed a new column. I called it date-added and the new condition is, date-added < $time-of-first-query for all subsequent queries. Then, the offset is just the number of articles written so far.

Order by then select incrementally

I have a table of > 250k rows of 'names' (and ancillary info) which I am displaying using jQuery Datatables.
My Users can choose any 'name' (Row), which is then flagged as 'taken' (and timestamped).
A (very) cut down version of the table is:
Key, Name, Taken, Timestamp
I would like to be able to display the 'taken' rows (in timestamp order) first and then the untaken records in their key order [ASC] next.
The problem would be simple, but, because of size constraints (both visual UI & data set size) My display mechanism paginates - 10 / 20 / 50 / 100 rows (user choice)
Which means a) the total number of 'taken' will vary and b) the pagination length varies.
Thus I can see no obvious method of keeping track of the pagination.
(My Datatable tells me the count of the start record and the length of the displayed records)
My SQL (MySQL) at this level is weak, and I have no idea how to return a record set that accounts for the 'taken' offset without some kind of new (or internal MySQL) numeric indices to paginate to.
I thought of:
Creating a temporary table with the key and a new numeric indices on
each pagination.
Creating a trigger that re-ordered the table when the row was
'taken'.
Having a "Running order" column that was updated on each new 'taken'
Some sort of cursor based procedure (at this point my hair was
ruffled as the explanations shot straight over the top of my head!)
All seem excessive.
I also thought of doing a lot of manipulation in PHP (involving separate queries, dependant on the pagination size, amount of names already taken, and keeping a running record of the pagination position.)
To the Human Computer (Brain) the problem is untaxing - but translating it into SQL has foxed me, as has coming up with a fast alternative to 1-3 (the test case on updating the "Running order" solution took almost three minutes to complete!)
It 'feels' like there should be a smart SQL query answer to this, but all efforts with ORDER BY, LIMITS, and the like fall over unless I return the whole dataset and do a lot of nasty counting.
Is there something like a big elephant in the room I am missing - or am I stuck with the hard slog to get what I need.
A query that displays the 'taken' rows (in timestamp order) first and then the untaken records in their key order [ASC] next:
SELECT *
FROM `table_name`
ORDER BY `taken` DESC, IF(`taken` = 1, `Timestamp`, `Key`) ASC
LIMIT 50, 10
The LIMIT values: 10 is the page size, 50 is the index of the first element on page 6.
Change the condition on IF(taken = 1,Timestamp,Key) with the correct condition to match the values you store in column taken. I assumed you store 1 when the row is 'taken' and 0 otherwise.

Consistent random ordering in a MySQL query

I have a database of pictures and I want to let visitors browse the pictures. I have one "next" and one "previous" link.
But what I want is to show every visitor anther order of the pictures. How can I do that? If I will use ORDER BY RANDOM() I will show sometimes duplicate images.
Can someone help me please? Thank you!
You can try to use seed in random function:
SELECT something
FROM somewhere
ORDER BY rand(123)
123 is a seed. Random should return the same values.
The problem arises from the fact that each page will run RAND() again and has no way of knowing if the returned pictures have already been returned before. You would have to compose your query in such a way that you can filter out the pictures already presented on the previous pages, so that RAND() will have fewer options to choose from.
An idea would be to randomize the pictures, select the IDs, store the IDs in the session, then SELECT using those IDs. This way, each user will have the pictures randomized, but they will be able to paginate through them without re-randomizing them on each page.
So, something like:
SELECT id FROM pictures ORDER BY RAND() LIMIT x if you don't have the IDs in the session already
Store the IDs in the session
SELECT ... FROM pictures WHERE id IN (IDs from session) LIMIT x
Another idea is to store in session the IDs that the user already saw and filter them out. For example:
SELECT ... FROM pictures ORDER BY RAND() LIMIT x if the session doesn't contain any ID
Append the IDs from the current query to the session
SELECT ... FROM pictures WHERE id NOT IN (IDs from session) ORDER BY RAND() LIMIT x
Another way seems to be to use a seed, as izi points out. I have to say I didn't know about the seed, but it seems to return the exact same results for the exact same value of the seed. So, run your usual query and use RAND(seed) instead of RAND(), where "seed" is a unique string or number. You can use the session ID as a seed, because it's guaranteed to be unique for each visitor.
You can seed the random function as suggested by izi, or keep track of visited images vs non-visited images as suggested by rdineiu.
I'd like to stress that neither option will perform well, however. Either will lead you to sorting your entire table (or the part of it of interest) using an arbitrary criteria and extracting the top n rows, possibly with an offset. It'll be dreadfully slow.
Thus, consider for a moment how important it is that every visitor should get a different image order. Probably, it'll be not that important, as long as things look random. Assuming this is the case, consider this alternative...
Add an extra float field to your table, call it sort_ord. Add an index on it. On every insert or update, assign it a random value. The point here is to end up with a seemingly random order (from the visitor's standpoint) without compromising performance.
Such a setup will allow you to grab the top n rows and paginate your images using an index, rather than by sorting your entire table.
At your option, have a cron job periodically set a new value:
update yourtable
set sort_ord = rand();
Also at your option, create several such fields and assign one to visitors when they visit your site (cookie or session).
This will solve:
SELECT DISTINCT RAND() as rnd, [rest of your query] ORDER BY rnd;
Use RAND(SEED). From the docs: "If a constant integer argument N is specified, it is used as the seed value." (http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand).
In the example above the result order is always the same. You simply change the seed (351) and you get a new random order.
SELECT * FROM your_table ORDER BY RAND(351);
You can to change the seed every time the user hits the first page.
Without seeing the SQL I'd guess you could try SELECT DISTINCT...

Mysql Insert data into table have a arranges question?

I found a weard problem with my MySQL DB.
sometime when I insert new data into it, the way it arranges the data is like a stack, for example
4 (newest)
3
2
1 (oldest)
...
how can I make it arranged like this?
1 (newest)
2
3
4 (oldest)
thanks all.
SELECT *
FROM TABLE
ORDER BY ID
You have to remember that when viewing/selecting data from a table without any ORDER BY specified does not garuantee any specific order.
The way you are view the data (unordered) can be due to any one of a lot of factos (the database engine, schema, page storage, page fragmentation, indexes, primary keys, or simply execution plan optimization).
The SQL standards specifically states that tables do not have a "natural" order. Therefore, the database engine is free to return a request without an ORDER BY in any order it wants to. The order may change from one request to another because most engines choose to return the data in whatever order they can get it to you the most rapidly.
It follows, therefore, that if you want the data out in a particular order you must include a column in your table whose job is to proxy for the order in which you added records to the table. Two common ways of doing this are using an autoincrement field which will be in numerical order from oldest to newest record, and a TIMESTAMP column which does just what it says. Once you have such a column you can use ORDER BY ColumnName when searching to get an ordered result set.