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.
Related
I have 2 tables with similar columns in MYSQL. I am copying data from one to another with INSERT INTO table2 SELECT * FROM table1 WHERE column1=smth. I have different columns as autoincrement and KEY in tables. When I use mysqli_insert_id i get the first one rather then last one inserted. Is there any way to get the last one?
Thanks
There is no inherit ordering of data in a relational database. You have to specify which field it is that you wish to order by like:
INSERT INTO table2
SELECT *
FROM table1
WHERE column1=smth
ORDER BY <field to sort by here>
LIMIT 1;
Relying on the order a record is written to a table is a very bad idea. If you have an auto-numbered id on table1 then just use ORDER BY id DESC LIMIT 1 to sort the result set by ID in descending order and pick the last one.
Updated to address OP's question about mysqli_insert_id
According to the Mysql reference the function called here is last_insert_id() where it states:
Important If you insert multiple rows using a single INSERT statement,
LAST_INSERT_ID() returns the value generated for the first inserted
row only. The reason for this is to make it possible to reproduce
easily the same INSERT statement against some other server.
Unfortunately, you'll have to do a second query to get the true "Last inserted id". Your best bet might be to run a SELECT COUNT(*) FROM table1 WHERE column1=smth; and then use that count(*) return to add to the mysqli_insert_id value. That's not great, but if you have high volume where this one function is getting hit a lot, this is probably the safest route.
The less safe route would be SELECT max(id) FROM table2 or SELECT max(id) FROM table2 Where column1=smth. But... again, depending on your keys and the number of times this insert is getting hit, this might be risky.
I have a MySQL chart table like this : PRIMARY KEY(ID), Name, Value, Date
I need to remove duplicates if "Name AND Value AND Date" are the same as existing row.
I have beneath a solution i found while ago and which worked (not 100%), but I don't understand the command in it's total because I'm only into BASIC MySQL... Can somebody explain me a little further...
definitely what is the x at the end ???
$delDups = "delete from chart where id not in (select * from (select min(id) from chart n group by value) x)";
mysql_query($delDups);
It appears to me that you could do it simpler, like this:
$delDups = "delete from chart where id not in (select min(id) from chart n group by value)";
In the subquery you are saing:
" Hey, take all the values and find the minimun id for the group of values"
So, imagine the result of the subquery as a list, like "(12, 13, 200)".. the NOT IN operator will take that list and use it to filter the result of the upper query and say "Give me all the results, less the ones where id is in this list"
I'm not sure if I explained it as expected...
You could add an unique key for all 3 columns:
ALTER IGNORE TABLE my_table
ADD CONSTRAINT uc_unic UNIQUE (Name, Value, Date)
As to that x,mysql permit aliases,essentially name shortcuts for convenience.
What you wrote will almost work, you just want to add the name and date to the GROUP BY clause. Something like this should do.
DELETE FROM chart
WHERE id NOT IN (
SELECT MIN(id)
FROM chart
GROUP BY name, value, date)
The DELETE FROM says you want to be deleting rows from a table. The WHERE clause says which rows you actually want to delete (missing it out will remove everything). The sub-query in the brackets will look through every combination of name, value and date and give you one id back from each combination. Putting it all together, the DELETE should now drop every row whose id isn't the smallest for each group.
Hope that helps!
Just working with a database and some tests were done recently which checked the integrity of the setup.
As a result, a lot of test entries were added which were then deleted. However, when new entries are added, the ID number value continues from after the entries added.
What I want:
ID increases by one from where it left off before the additional rows were added:
4203, 4204, 4205, 4206 etc.
What is happening:
ID increases by one from after the additional rows ID:
4203, 4204, 6207, 6208 6209 etc.
Not sure where to fix this...whether in phpmyadmin or in the PHP code. Any help would be appreciated. Thanks!
I have ran into this before and I solve it easily with phpMyAdmin. Select the database, select the table, open the operations tab, and in the Table Options set the AUTO_INCREMENT to 1 then click GO. This will force mysql to look for the last auto incremented value and then set it to the value directly after that. I do this on a manually basis that way I know that when a row is skipped that it was not from testing but a deletion because when I test and delete the rows I fix the AI value.
I don't think there's a way to do this with an auto-incrementing ID key.
You could probably do it by assigning the ID to (select max(id) + 1 from the_table)
You could drop the primary key then recreate it, but this would reassign all the existing primary keys so could cause issues with relationships (although if you don't have any gaps in your primary key you may get away with it).
I would however say that you should accept (and your app should reflect) the possibility of missing IDs. For example in a web app if someone links to a missing ID you would want a 404 returned not a different record.
There should be no need to "reset" the id values; I concur with the other comments concerning this issue.
The behavior you observe with AUTO_INCREMENT is by design; it is described in the MySQL documentation.
With all that said, I will describe an approach you can use to change the id values of those rows "downwards", and make them all contiguous:
As a "stepping stone" first step, we will create a query that gets a list of the id values that we need changed, along with a proposed new id value we are going to change it to. This query makes use of a MySQL user variable.
Assuming that 4203 is the id value you want to leave as is, and you want the next higher id value to be reset to 4204, the next higher id to be reset to 4205, etc.
SELECT s.id
, #i := #i + 1 AS new_id
FROM mytable s
JOIN (SELECT #i := 4203) i
WHERE s.id > 4203
ORDER BY s.id
(Note: the constant value 4203 appears twice in the query above.)
Once we're satisfied that this query is working, and returning the old and new id values, we can use this query as an inline view (MySQL calls it a derived table), in a multi-table UPDATE statement. We just wrap that query in a set of parentheses, and give assign it an alias, so we can reference it like a regular table. (In an inline view, MySQL actually materializes the resultset returned by the query into a MyISAM table, which probably explains why MySQL refers to it as a "derived table".)
Here's an example UPDATE statement that references the derived table:
UPDATE ( SELECT s.id
, #i := #i + 1 AS new_id
FROM mytable s
JOIN (SELECT #i := 4203) i
WHERE s.id > 4203
ORDER BY s.id
) n
JOIN mytable t
ON t.id = n.id
SET t.id = n.new_id
ORDER BY t.id
Note that the old id value from the inline view is matched to the id value in the existing table (the ON clause), and the "new_id" value generated by the inline view is assigned to the id column (the SET clause.)
Once the id values are assigned, we can reset the AUTO_INCREMENT value on the table:
ALTER TABLE mytable AUTO_INCREMENT = 1;
NOTE: this is just an example, and is provided with the caveat that this should not be necessary to reassign id values. Ideally, primary key values should be IMMUTABLE i.e. they should not change once they have been assigned.
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).
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.