MySQL Update by Row number - mysql

I need to update rows by their number(not AI ID, cause some of the rows may will be removed). How can I do this?
I mean something like this:
UPDATE cars SET idx = value WHERE row_number = i
I would do this in a 'for' statement, and i is the integer of my statement. So I would update every row in the statement.
Sorry for my bad english, and thanks!

Here's a pure MySQL solution:
/*test data*/
create table foo (id int auto_increment primary key, a int);
insert into foo (a) values (10), (11), (12);
/*update statement*/
update foo
set a = 5
where id = (
select id from (
select id, #rownum:=#rownum + 1 as rownumber
from foo, (select #rownum:=0) vars order by id
) sq where rownumber = 2
);
Results in:
| ID | A |
-----|----|--
| 1 | 10 |
| 2 | 5 |
| 3 | 12 |
Feel free to ask if you have any questions about this.
Also, note the order by id in there. It's important, cause in a database there is no first or last row. Without an order by clause theoretically there could be each time a different result.
You can also see it working live here in an sqlfiddle.

i don't know this about mysql but you can do this in php
$row_number=? ;//the row no of mysql you want to change the id
$id=? ;//the new id
mysql_connect //do it yourself
$query="select 8 from tablename"; //the query
$result=mysql_query($qyery,$conn);
$count=0;
while($row=mysql_fetch_array($result)) // fetch each row one by one an put data in array $row
{
$count++; //increment count means the no of rows are incermented
if($count==$rownumber) //the row where you want to edit the id
{
$query1="update tablename set id='".$id."' where id=".$row["id"]; //new query on that particular row
$result1=mysql_query($query1,$conn);
}
}
this will work , just modify this code according to your use

Related

how to sort data with multiple data sets within a single row?

How can I sort a mySQL data set based on a certain set that is stored randomly in each row? (i.e., the 'field' I want to sort is like [x-yyyyyyy], where 'x' is the initial number I am looking for, and 'yyyyy' is what I want to sort) (EDIT: see at very end for the 'mysql' version).
I.e., this is my data in a mySQL field (lets say called 'items'):
row 1: [1-283482][3-4848484][6-484868]
row 2: [6-484444][1-1111][5-4338484]
row 3: [7-484444][1-9999][3-4338484]
I want to "sort" any field that starts with a "[1-", and then sort the 2nd half numerically?
So, for example, if I was sorting ascending, it would give me the results:
row 2: [6-484444][1-1111][5-4338484]
row 3: [7-484444][1-9999][3-4338484]
row 1: [1-283482][3-4848484][6-484868]
(because removing the '[1-', the order is:
"1111"
"9999"
"283482"
in terms of numerical values?)
and of course descending would be:
row 1: [1-283482][3-4848484][6-484868]
row 3: [7-484444][1-9999][3-4338484]
row 2: [6-484444][1-1111][5-4338484]
Thanks very much!
In other words (from a MYSQL perspective), the data looks like this:
CREATE TABLE `testTable` (
`autoID` int(11) NOT NULL,
`item` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `testTable` (`autoID`, `item`) VALUES
(1, '[1-283482][3-4848484][6-484868]'),
(2, '[6-484444][1-1111][5-4338484]'),
(3, '[7-484444][1-9999][3-4338484]');
ALTER TABLE `testTable`
ADD PRIMARY KEY (`autoID`);
And I'd like to be able to do something like:
Select `item` from `testTable` order by '[1-*****]' asc
If all the rows contain this substring '[1-' in the column item then this should do:
select * from testTable
order by substring(item, locate('[1-', item) + 3) + 0
See the demo.
Results:
| autoID | item |
| ------ | ------------------------------- |
| 2 | [6-484444][1-1111][5-4338484] |
| 3 | [7-484444][1-9999][3-4338484] |
| 1 | [1-283482][3-4848484][6-484868] |
If there are also other rows that do not contain '[1-' and you want these rows at the end:
select * from testTable
order by item not like '%[1-%',
substring(item, locate('[1-', item) + 3) + 0
you can use the function substring of mysql for get the number on right
Example:
SELECT string,CONVERT(SUBSTRING_INDEX(REPLACE(SUBSTRING_INDEX('[1-283482][3-4848484][6-484868]','][',1),'[',''),'-',-1),SIGNED) as num from table
ORDER BY num desc
other option is whit SUBSTRING_INDEX
SELECT item,CONVERT(SUBSTRING_INDEX(REPLACE(SUBSTRING_INDEX(item,'][',1),'[',''),'-',-1),SIGNED) as num from testTable
ORDER BY num desc

Update table row value to a random row value from another table

I have 2 MySQL tables.
One table has a column that lists all the states
colStates | column2 | column 3
------------------------------
AK | stuff | stuff
AL | stuff | stuff
AR | stuff | stuff
etc.. | etc.. | etc..
The second table has a column(randomStates) with all NULL values that need to be populated with a randomly selected state abbreviation.
Something like...
UPDATE mytable SET `randomStates`= randomly selected state value WHERE randomStates IS NULL
Can someone help me with this statement. I have looked around at other posts, but I don't understand them.
this works for me with trial data in SQLite:
UPDATE mytable
SET randomStates = (SELECT colStates FROM
(SELECT * FROM first_table ORDER BY RANDOM())
WHERE randomStates IS NULL)
without the first SELECT portion, you end up with the same random value inserted into all the NULL randomStates field. (i.e. if you just do SELECT StateValue FROM counts ORDER BY RANDOM() you don't get what you want).

MySQL retrieving INSERT parameters retrieved by SELECT

If I have table structure as so:
CREATE TABLE a (
aid INT AUTO_INCREMENT,
acol1 INT,
acol2 INT,
PRIMARY KEY(aid);
)
CREATE TABLE b (
bid INT AUTO_INCREMENT,
bcol INT,
PRIMARY KEY(bid);
)
and run the statement:
`INSERT INTO a SET acol1 = (SELECT MAX(acol1) + 1 as newMax FROM a WHERE id = ?)
Is there anyway for me to retrieve the value of newMax after the query is executed? I am looking for something similar to last_insert_id() in PHP but for temporary values in the query.
Obviously I am trying to not query the database again if possible.
EDIT:
Actual situation:
CREATE TABLE group (
group_id INT AUTO_INCREMENT,
PRIMARY KEY(group_id)
) ENGINE = MyISAM;
CREATE TABLE item (
group_refid INT, --references group.group_id
group_pos INT, --represents this item's position in its group
text VARCHAR(4096), --data
PRIMARY KEY(group_refid, group_pos)
) ENGINE = MyISAM;
So the issue is that when I add a new item to a group, I need to make its
group_pos = MAX(group_pos) WHERE group_refid = ?
which would require a query with something like:
INSERT INTO item (group_refid, group_pos) SET group_refid = 1, group_pos = (SELECT MAX(group_pos) + 1 FROM item WHERE group_refid = 1);
As you know, this query does not work. There is added complexity that there may not be an item entry yet for a particular group_id.
I am trying to get this all into one atomic statement to prevent race conditions.
INSERT INTO item (group_refid,group_pos)
SELECT 1, (
SELECT IFNULL(MAX(group_pos),0) + 1
FROM item
WHERE group_refid=1
);
However, if we're talking MyISAM tables explicitly, not another engine, this would work:
mysql> CREATE TABLE items (group_refid INT, group_pos INT AUTO_INCREMENT, PRIMARY KEY(group_refid,group_pos)) ENGINE=MyISAM;
Query OK, 0 rows affected (0.12 sec)
mysql> INSERT INTO items (group_refid) VALUES (1),(2),(1),(1),(2),(4),(2),(1);
Query OK, 8 rows affected (0.02 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM items ORDER BY group_refid, group_pos;
+-------------+-----------+
| group_refid | group_pos |
+-------------+-----------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 4 | 1 |
+-------------+-----------+
However, that AUTO_INCREMENT on a second column in the PK is not portable to another database engine.
you cant. insert query is for insering not selecting.
You must run other query like that
SELECT MAX(acol1) + 1 as newMax FROM a WHERE acol2 = ?
for more read this
I think you can do:
INSERT INTO b
SET bcol = (SELECT #acol := MAX(acol1) + 1 as newMax FROM a WHERE acol2 = ?);
Then you can use the variable #acol to get the value you want.
EDIT:
Is this what you want?
INSERT INTO item (group_refid, group_pos)
SELECT 1, MAX(group_pos) + 1
FROM item
WHERE group_refid = 1;
Not directly in the statement, no. You'll need a separate statement to retrieve values.
But, you could "capture" the value from the SELECT into a user-defined variable, and then retrieve that with a SELECT (in the same database session), if you needed to "know" the value returned from the SELECT.
For example:
INSERT INTO b (bcol)
SELECT #bcol := (MAX(a.acol1) + 1) AS newMax
FROM a WHERE a.acol2 = ?)
SELECT #bcol + 0 AS new_bcol
NOTE:
Note that the user-defined variable assigned in the select is subject to modification elsewhere in the session, for example, it could be overwritten by the execution of a trigger defined the target table of the INSERT.
As an edge case, not that anyone would do this, but it's also possible there might be a BEFORE INSERT trigger that modifies the value of bcol, before it gets inserted. So, if you need to "know" the value that was actually inserted, that would be available in an AFTER INSERT trigger. You could capture that in a user-defined variable in that trigger.
Running a second, separate query against the a table is subject to a race condition, a small window of opportunity for a another session to insert/update/delete a row in table a, such that it's possible that a second query could return a different value than the first query... it might not be the value that was retrieved the first time. Unless of course you are within the context of an InnoDB transaction with REPEATABLE READ isolation level, or you've implemented some concurrency-killing locking strategy.

Zend Db / Mysql - Insert with Select

I am trying to find the best way to do this, better if I could use Zend_db_table.
Basically I am inserting a row and one of the values comes from the same DB, this value changes constantly so I need to be sure the data inserted is valid.
I can't query first for the value and then append it to the insert query because between the two queries the data could change and I end up inserting the wrong value. I wonder if LOCKING the table is the way to go or if Zend has a shortcut.
I'm using Mysql.
[EDITED]
For example: This table has a field called item_number, and for each new row I take the last item_number+1 (from the same item_family) and insert with it. It is a manual increment.
TABLE ITEMS
| item_id | item_family | item_number | name |
| 15 | 1 | 10 | Pan |
| 16 | 2 | 1 | Dress |
| 17 | 1 | 11 | Spoon |
In this example you see that the next row from item_family 1 has its item_number = 11 because the previous row from the same item_family was 10.
Thanks!
My solution (using Zend) was to LOCK the table, than query the item_number, append the result to the insert query, insert and UNLOCK the table. Here is how to LOCK and UNLOCK:
$sql = "LOCK TABLE items WRITE";
$this->getAdapter()->query($sql);
//run select to get last item_number
//append result to insert array
//insert
$sql = "UNLOCK TABLES";
$this->getAdapter()->query($sql);
Another way is to write the query so the value would be selected durint the insert. Here is an example:
$sql = INSERT INTO items (item_id, item_family, item_name, item_number)
VALUES (item_id, item_family, item_name, (SELECT item_number FROM... )+1);
$this->getAdapter()->query($sql);
More info about this kind of query in MySQL Web
Provided that item_id is the primary key of your table, and it set as auto increment field, the Zend_Db_Table::insert() function will return the primary key of the row just you inserted.
For example:
$table = new Items();
$data = array(
'item_family' => '1',
'item_number' => '10',
'name' => 'Pan'
);
$itemId = $table->insert($data);
You can also call directly the mysql last inserted id function:
$itemId = $this->getAdapter()->lastInsertId('items');

Mysql auto_increment proceed with lowest value

My problem is: I have a table with an auto_increment column. When I insert some values, all is right.
Insert first row : ID 1
Insert second row : ID 2
Now I want to insert a row at ID 10.
My problem is, that after this there are only rows inserted after ID 10 (which is the normal behaviour ).
But I want that the database first fills up ID 3-9 before making that.
Any suggestions?
EDIT:
To clarify: this is for an URL shortener I want to build for myself.
I convert the id to a word(a-zA-z0-9) for searching, and for saving in the database I convert it to a number which is the ID of the table.
The Problem is now:
I shorten the first link (without a name) -> ID is 1 and the automatically name is 1 converted to a-zA-Z0-9 which is a
Next the same happenes -> ID is 2 and the name is b, which is 2 converted.
Next interesting, somebody want to name the link test -> ID is 4597691 which is the converted test
Now if somebody adds another link with no name -> ID is 4597692 which would be tesu because the number is converted.
I want that new rows will be automatically inserted at the last gap that was made (here 3)
You could have another integer column for URL IDs.
Your process then might look like this:
If a default name is generated for a link, then you simply insert a new row, fill the URL ID column with the auto-increment value, then convert the result to the corresponding name.
If a custom name is specified for a URL, then, after inserting a row, the URL ID column would be filled with the number obtained from converting the chosen name to an integer.
And so on. When looking up for integer IDs, you would then use the URL ID column, not the table auto-increment column.
If I'm missing something, please let me know.
You could do 6 dummy inserts and delete/update them later as you need. The concept of the auto increment, by design, is meant to limit the application's or user's control over the number to ensure a unique value for every single record entered into the table.
ALTER TABLE MY_TABLE AUTO_INCREMENT = 3;
You would have to find first unused id, store it as user variable, use as id for insert.
SELECT #id := t1.id +1
FROM sometable t1 LEFT JOIN sometable t2
ON t2.id = t1.id +1 WHERE t2.id IS NULL LIMIT 1;
INSERT INTO sometable(id, col1, col2, ... ) VALUES(#id, 'aaa', 'bbb', ... );
You will have to run both queries for every insert if you still have gaps, its up to you to decide whether it is worth doing it.
not 100% sure what you're trying to achieve but something like this might work:
drop table if exists foo;
create table foo
(
id int unsigned not null auto_increment primary key,
row_id tinyint unsigned unique not null default 0
)
engine=innodb;
insert into foo (row_id) values (1),(2),(10),(3),(7),(5);
select * from foo order by row_id;
+----+--------+
| id | row_id |
+----+--------+
| 1 | 1 |
| 2 | 2 |
| 4 | 3 |
| 6 | 5 |
| 5 | 7 |
| 3 | 10 |
+----+--------+
6 rows in set (0.00 sec)