Unique Primary Id exchange in on mysql? - php

i got an sql table which contains data for a menu in the php page.
SELECT * FROM `hizlierisim` ORDER BY id LIMIT 0 , 10
it is ordered by id row.but im asked to add order control on admin panel.
So there will Up&Down Buttons to re-arrange menu items.
i guess there is two ways to do this
one is to create a row called 'order' and change sql query to:
SELECT * FROM `hizlierisim` ORDER BY `order` LIMIT 0 , 10
or
exchange id's of the columns that we wanted to move.
and still use same sql:
SELECT * FROM `hizlierisim` ORDER BY id LIMIT 0 , 10
id method seems easier but i wonder if there is a possibility to exchange id's of two columns on mysql?

Messing with primary key fields just to satisfy some arbitrary ordering requirement is a bad idea. Especially in a foreign key situation. Add an 'order' column (which is a reserved word, by the way, so use something else if you want to save yourself some pain) is the practical option.

Changing PK IDs for this sort of functionality is a very bad practice; far better to introduce an ordering column and use that to sort by. Obviously don't call it ORDER as that's a reserved word...

The id of a row should be static, a permanent unique identifier for the record, such that it can be stored as a foreign key elsewhere.
Creating the "order_id" as you suggest would be preferable. This can be changed to any value you like without a side-effect, it's for ordering, changing it only effects ordering.
In terms of "swapping" values, there isn't anything I'm aware of, you just need to code it yourself.
Either...
BEGIN TRANSACTION
UPDATE x SET order_id = NULL WHERE order_id = 11
UPDATE x SET order_id = 11 WHERE order_id = 10
UPDATE x SET order_id = 10 WHERE order_id IS NULL
COMMIT TRANSACTION
(or similar)
Or maybe something like...
UPDATE
x
SET
order_id = CASE order_id WHEN 11 then 10 ELSE 11 END
WHERE
order_id IN (10,11)

By "exchange" I assume you're talking about updating primary key values of two columns which is horrible, HORRIBLE idea - I can't stress enough how bad it is and what implications it might have. I suggest you do some reading on what primary keys are and why you should never play with them.
Add another field and update it with values 0, 1 and so on and order on that column. You can also specify multiple columns in your ORDER BY clause which allows you to order by primary key and some other column(s).

Related

Adding a Row into an alphabetically ordered SQL table

I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.

How to Create a MySQL Table with the Primary Key sorted by DESC and keep it that way after INSERTing new rows?

I need to create an InnoDB table that I will use to add data to and constantly fetch the most recent 10 rows added to it. To avoid having to do an ORDER BY with every SELECT query to get those last 10 rows, I would like to have the table itself ordered by the Primary Key in DESC order so that I can skip the ORDER BY entirely and just do a SELECT ... LIMIT 10, which should automatically pull the most recent 10 rows added to the table.
How can I do that? Is it as simple as adding ORDER BY [PRIMARYKEY] DESC to the CREATE TABLE query? Will the table continue to be sorted in DESC order even after INSERTing new rows?
A RDBMS never provides any guarantees on the order of the rows in any of the tables it manages. The only way to get a specific order is to ask for one. For the case of MySQL, the rows happens to be sorted by the primary key in ascending order often time when that key is in auto increment mode, but it's not a guaranteed property.
Use ORDER BY on your queries to get the desired result.
On the other hand, the ordering will be faster if the primary key type is BTREE (which is the default on most engine).
The sorting direction isn't yet used on MySQL 5.5.

Retrieving the most recent entry in a database table with a certain value

I have a table with three fields - userID, couponID, last_couponID.
When the user accesses a coupon, I run this query:
mysql_query("INSERT INTO users_coupons (userID, couponID) VALUES ('$recordUserID', '$recordCoupID')");
Further, I have another query that should insert the last couponID into the field last_couponID, by polling the database table and finding the most recent result for the current userID.
I believe it is as such:
SELECT couponID FROM users_coupons ORDER BY userID LIMIT 1
Am I correct? Or should I use a different query?
Like this:
userID couponID
1 3
1 13
1 23
2 5
2 3
So if I wanted userID 2's latest coupon, it'd be '3', and for userID 1, it'd be '23'. I just want the last entry in the database table where the userID matches a value I provide.
I would just add a primary key (autoincrementing) to the users_coupons table.
When you want the latest coupon of a user,SELECT couponID FROM users_coupons WHERE userID = ? ORDER BY id DESC LIMIT 1
Assuming that couponID is numeric, and the last couponID for a certain userId is the greatest (as a number), you can do:
SELECT MAX(couponID) AS lastCouponId FROM users_coupons WHERE userId = <put here the user id>
EDIT: since you've edited your question, I edit my answer.
You have to add an auto-increment primary key, otherwise you can't know exactly which entry is the last one. When I answered, I supposed the last coupon for a certain userId was the one with the greatest couponId. Are you sure you can't just make things work this way?
Something along the lines of...
SELECT couponID
FROM users_coupons
WHERE userID = <current user id>
ORDER BY <primary key of user_coupons table if it's an identity column> DESC
LIMIT 1
...is more appropriate. Your query as it stands doesn't do anything with the 'current' user ID.
If you are actually after the highest couponID then SELECT MAX(couponID)... as suggested by Giacomo is a good idea - coupled with a check for the UserID matching the current user ID.
#Giacomo's answer is valid if you are incrementing the CouponID reliably as an identifier. If you have merged in data or are adjusting this value any other way then it may not be correct.
In theory, if you consider CouponID to be a surrogate key then you cannot use it to explicitly determine insert order. If you intend for it to be used for the purpose of insert order then you also need to make sure your supporting code and DB maintenance plans promote this use.
I contend that the "correct" method is to also store a DateTime

mysql find smallest + unique id available

i have a column ID and something like 1000 items, some of then were removed like id=90, id=127, id=326
how can i make a query to look for those available ids, so i can reuse then for another item?
its like a min(ID) but i want to find only the ids that are NOT in my database, so if i remove a item with the ID = 90, next time i click on ADD ITEM i would insert it as id = 90
You can get the minimum available ID using this query:
SELECT MIN(t1.ID + 1) AS nextID
FROM tablename t1
LEFT JOIN tablename t2
ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL
What it does is that it joins the table with itself and checks whether the min+1 ID is null or not. If it's null, then that ID is available. Suppose you have the table where ID are:
1
2
5
6
Then, this query will give you result as 3 which is what you want.
Do not reuse IDs. You usually have way enough available IDs so you don't have to care about fragmentation.
For example, if you re-use IDs, links from search engines might point to something completely unrelated from whatever is in the search index - showing a "not found" error is much better in such a case.
It's against the concept of surrogate keys to try to reuse IDs
The surrogate key is good because it idetifies the record itself, not some object in real life. If the record is gone, the ID is gone too.
Experienced DB developers are not afraid of running out of numbers because they know how many centuries it is needed to deplete, say, long integer numbers.
BTW, you may experience locking or violating uniqueness problems in a multithreaded environment with simultaneous transactions trying to find a gap in the ID sequence. The auto increment id generators provided by DB servers usually work outside the transactions scope and thus generate good surrogate keys.
Further reading: Surrogate keys
the query is like :
SELECT MIN(tableFoo.uniqueid + 1) AS nextID
FROM tableFoo
LEFT JOIN tableFoo tf1
ON tableFoo.uniqueid + 1 = tf1.uniqueid
WHERE tf1.uniqueid IS NULL
Note that the answers by shamittomar and Haim Evgi don't work if the lowest ID is free. To allow for the refilling the lowest ID, pre-check to see whether it is available:
SELECT TRUE FROM tablename WHERE ID = 1;
If this returns anything, then the ID of 1 is not free and you should use their answer. But if the ID of 1 is free, just use that.
In my personal opinion. Instead of removing the row from the auto increment it would be light years less expensive to have Boolean Column for "Removed" or "Deleted" and for extra security over right the row with blanks while you set the removed flag.
UPDATE table SET data=" ", removed = TRUE WHERE id = ##
(## is the actual id btw)
Then you can
SELECT * FROM table WHERE removed = TRUE ORDER BY id ASC
This will make your Database perform better and save you dough on servers. Not to mention ensure no nasty errors occur.
Given that your database is small enough, the correct answer is to not reuse your ids at all and just ensure its an auto incremented primary key. The table is a thousand records, so you can do this without any cost.
However, if you have a table of a few million records/longer id, you will find that the accepted answer wont finish in sensible time.
The accepted answer will give you the smallest of these values, correctly so, however, you are paying the price of not using an auto increment column, or if you have one, not using the auto increment column as the actual ID as it is intended (Like me, else I wouldn't be here). I'm at the mercy of a legacy application were the ID isn't the actual primary key is being used, and is randomly generated with a lolgorithm for no good reason, so I needed a means to replace that since upping the column range is now an extremely costly change.
Here, it is figuring out the entire
join between the entirety of t1 and t2 before reporting what the min of those joins is. In essence, you only care about the first NULL t1 that is found, regardless of whether it actually is the smallest or not.
So you'd take the MIN out and add a LIMIT of 1 instead.
edit : Since its not a primary key, you will also need to check for not null, since a primary key field cant be null
SELECT t1.ID + 1 AS nextID
FROM tablename t1
LEFT JOIN tablename t2
ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL
AND t1.ID IS NOT NULL
LIMIT 1
This will always give you an id that you can use, its just not guaranteed to always be the smallest one.

Selecting a single row in MySQL

I am using MySQL, I have a table that has 9 columns. One of them is the primary key.
How can I select a single row, by the primary key or column 8 or 4?
If I understand your question correctly:
SELECT * FROM tbl WHERE id = 123 OR colname4 = 'x' OR colname8 = 'y' LIMIT 1
The 'LIMIT' keyword makes sure there is only one row returned.
select *
from MyTable
where MyPrimaryKey = 123
Columns in SQL don't have a defined 'order'. Database systems generally keep track of an order for display purposes, but it doesn't make sense to ask a database to select a column by number. You need to know the column's name in order to query its contents.
The same thing goes for the primary key (which, incidentally, may not be just a single column). You have to know which column it is, and what that column is named, in order to execute a query.
If you don't know these things, or need to figure them out dynamically, then
DESCRIBE tablename;
will tell you the names of each column, and whether it is part of the primary key or not. It will return a table that you can read, like any other result.

Categories