I had a hard time with the title, so let me explain.
What I'm doing is using the jQuery UI to create sortable list elements on a page. Once the order is submitted, php assigns an incrementing value to the list elements based on their order, drops the existing id column, creates a new id column and inserts each list elements value WHERE title=x. This creates the proper order of ID's, and is working fine.
What I'd like to do now is change the column to auto_increment, such that if I insert a new entry, the id is assigned automatically, one number higher than the greatest number generated by the php script. I'm not using any foreign keys or anything, just this simple table.
Is this possible?
My mistake, I misread your question. You do not want to use the database itself to provide numbering based on your sort order. You can however use the SQL query itself to return an incrementing field. One sec and I'll update with that info...
Ok, here it is:
you need to use a variable like
set #n=0;SELECT
#n:=#n+1 as 'n',
col1,
col2
from table
However, i highly recommend you just create the numbering in your php code if at all possible.
----------------Original Post----------------
This is pretty easy with phpmyadmin. Let me know if your unable to install that and I'll dig up the necessary SQL.
All heck, here is the SQL:
alter table t1 modify f1 int(4) auto_increment
alter TABLE tbl auto_increment = xxx; //change xxx to be the next id it should use
you may need to run these in opposite order depending on your existing data set it will fail to add auto_increment if you don't change the value of auto_increment to be something not already in use.
Related
Ok, here's what I wanna do.
Table1(globalID [primary key, autoincremented] (is a global id i would use in PHP))
Table2 & table3(ID* [foreign primary key, referencing to globalID], other columns after this, different for each of the tables 2 and 3);
What I wannt to know is if there is a way, and how, to make it so that when I insert a row in table2 or table3 the globalID in talbe1 gets populated and it's value also inserted in table2 or table3 accordingly as an ID. I assume it would be accomplished with a trigger, but triggers are not my forte so if that's the only way it can be done please provide an example.
I was also thinking of expanding it to this scenario:
Table1(globalID [primary key, autoincremented] (is a global id i would use in PHP),
OtherID [an UUID]);
Table2 & table3(ID* [foreign primary key, referencing to OtherID], other columns after this, different for each of the tables 2 and 3);
But in that case there is still the almost nonexistent possibility that 2 users might generate the same UUID while inserting a new row in some table. I was wondering if i could avoid that by making the keys generated by the sql server automatically without me having to code it PHP server side.
If anyone has had this problem worked out and can also point out other things i need to watch out for or take into account please point them out. Also please provide an example of the solution.
EDIT:
#John B.
EDIT BY TosheX
thank you for the reply. I have been reading up on this in the meantime and i already have a solution outside of SQL (in php). Basically I use Yii PHP framework in which I create a model of the table, and create an active record to populate a new row. now when I do that the ID in table1 is generated, and afterwards I still have a variable that points to that populated row and I can just read the generated ID since it's automatically fetched (without having to check for the last record in the database, which may return the record someone created milliseconds after me). Afterwards I just need to create a row inside the appropriate table2 or 3 and assign the already generated value for the ID.
i found the idea here:
http://www.yiiframework.com/forum/index.php/topic/14593-alternate-for-mysql-insert-id/
I really wanted an inbuilt solution in the database, but since I have experience with databases and do know enough about triggers (enough to not like them :D ) i know it's a very tricky code to get right so I was wondering if there are alternatives to auto-populate or something.
Still, I really appreciate your response, since you took your time and all. I have been working in msSQL more too, and I find logic in what you said. UUID in mySQL is the same as GUID in msSQL and I have considered that too as you can see.
Taking all this into account I will go with the solution i found, but I will accept your answer since you did try to help out, and you did bring some good ideas to the table.
Thanks again.
I'm a mssql person, but I dont think it is possible, unless you can create a "BEFORE INSERT" trigger for your db (and even then it will be problematic), because:
Whatever the ID of Tables 2 & 3 is, be it an integer or a guid, these are primary keys: Being a primary key, this column will not allow nulls, yet what you require is essentially to create new rows in these tables, with this column null, and then generate a new row in Table1, and use the new value in that table to update the new row in either Table2 or Table3.
Therefore, you'll probably need to either:
Do a solution in code (ie outside of SQL) whereby you cause the creation of a new row in Table1 first, then use this value when subsequently creating in Table2/3, or:
On tables2/3 have a autoincremented column for your primary key lets call it "PK", then have ID as a separate ordinary FK but which allows nulls, plus a trigger as follows (though you might need to fiddle with the syntax a little bit, because I am a mssql person, and I don't know your db's syntax) :-(
Also this example is designed to work with a multiple row insert, and to achieve this uses a cursor, and my syntax for cursors is dodgy at best even in mssql!
CREATE TRIGGER trg_Table2 ON dbo.Table2
FOR INSERT /* might be AFTER INSERT etc */
AS BEGIN
SET nocount on;
Declare ICursor Scroll For SELECT PK FROM Inserted;
Declare #PK int,
#GlobalID int,
#ID guid;
OPEN ICursor
FETCH Next From ICursor INTO #PK
WHILE ##Fetch_Status BEGIN
INSERT Table1 (OtherID) VALUES (NewID());
SELECT #GlobalID = ##Identity
SELECT #ID = OtherID FROM Table1 WHERE GlobalID = #GlobalID
UPDATE Table2 SET ID = #ID WHERE PK = #PK
FETCH Next FROM ICursor INTO #PK
END
Close ICursor
Deallocate ICursor
END
Hope this helps
In my MySQl table I have two fields, id and order. id is an auto-incrementing primary key and I want order's initial value to match this, but to also be editable, not a key and with no uniqueness constraints. How can my database insert method achieve this? Is it possible to do so without requerying to find the last inserted id?
I'm using paris/idiorm so a solution making use of their features would be handy, although plain SQL and php is fine too.
In MySQL (since version 5.0.2) you can create trigger.
Try this on non-production database:
create trigger default_order_value AFTER INSERT ON orders
UPDATE order SET order = id WHERE id = new.id;
It may not work in that way as you wish, but you can edit it. This is another trigger example:
CREATE TRIGGER default_order
BEFORE UPDATE ON orders
REFERENCING NEW ROW AS n
n.order = n.id;
I have a mysql database and some php that allows you to create an entry in the database, update an entry, and view the entries as a web page or xml. What I want to do is add a function to move an entry in the database up or down by one row, or, send to the top of the database or bottom.
I've seen some online comments about doing this type of thing that suggested doing a dynamic sort when displaying the page, but I'm looking for a persistent resort. I've seen one approach suggested that would be to have a separate "sort" field in the database that is agnostic of the actual database sort key, but I'm not sure why that would be better than actually re-ordering the database
Here is a dump of the table structure:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `hlnManager`
--
-- --------------------------------------------------------
--
-- Table structure for table `hln_stations`
--
CREATE TABLE IF NOT EXISTS `hln_stations` (
`id` int(6) NOT NULL auto_increment,
`station_title` varchar(60) NOT NULL default '',
`station_display_name` varchar(60) NOT NULL default '',
`station_subtitle` varchar(60) NOT NULL default '',
`station_detailed_description` text NOT NULL,
`stream_url_or_playlist_url` text NOT NULL,
`link_type` varchar(25) NOT NULL default '',
`small_thumbnail_graphic_url` text NOT NULL,
`large_thumbnail_graphic_url` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
Not sure what you mean by "Reordering" the database... SQL Databases typically do not make any guarantees on what order (if any) they will return records in short of an ORDER BY clause.
You need a "SortOrder" type column. I suggest you make it an int with a unique key.
You need a way to update this "SortOrder" column via the UI
Easy to program, easy to use: Implement a simple drag+drop interface in HTML using jQuery or whatever javascript library works for you. In the on-complete method (or in response to a save button), trigger an ajax call which will simply send an array of ids in the correct order. On the database side, loop over it and update the SortOrder accordingly, starting at 1, then 2, etc...
Harder to program, hard to use: Implement a classical move-up and move-down buttons. When clicked, send the id and action (eg, up, down) to the server. There are several strategies to handle this update, but I will outline a couple:
Assuming the user clicked "move up", you can swap IDs with the previous record.
Find the previous record: SELECT id FROM hln_stations WHERE SortOrder < (SELECT SortOrder FROM hln_stations WHERE id = ...) ORDER BY SortOrder DESC LIMIT 1
Run two update statements, swapping the SortOrder. Reverse for moving down. Add special code to detect top or bottom.
etc...
There are other ways, but for a web interface, I suggest you do Drag+Drop, as the users will love it.
Databases are not "stored" in any order. They are stored in whatever way is convenient for the storage subsystem. If you delete a record, a new record may use the space of the old record "inserting" itself into the database. While it may seem like the database always returns records in a particular order, you can't rely on it.
The ONLY way to assure a sort order is to have a field to sort on.
Dont know where you can find example to find example. but you can look the following code it is very basic:
Let id is your primary key and there is a column sort_order. You want to store primary keys in the following order: 5,4,3,6,8,7,9,10,2,1.
then you store them in an array:
$my_sorted = array(5,4,3,6,8,7,9,10,2,1);
then you update your table:
update `mytable` set `sort_order` = (index of $my_sorted) WHERE `id`=(array value of that index).
Instead of doing many queries you can do it in one query like:
$query = "UPDATE `mytable` SET sort_order= CASE id ";
foreach($my_sorted as $key=>$val){
$query .= " WHEN '$val' THEN $key ";
}
$query .="END";
Then you run $query in mysql.
After updating table you can select from mytable with order by sort_order asc or desc.
hope this helps.
"re-ordering" the database would require two records swapping primary keys, or most likely they would need to have all data except the primary keys be swapped. this would most likely be undesireable, since the primary key should be the one way you can consistently refer to a particular record.
The separate order field would be the way to go. Just make sure that you put an index on the order field so that things stay speedy.
There is no way to find out in which order databases stores data. When we query to database, we specify the field name that we want our data to be sorted by.
In your case, I would add a new column: sequence int(10). and write php function to change/update sequence number. when i will use select query, I will order by sequence number.
I would like write a php script that merges several databases, and I would like to be sure of how to go around it before I start anything.
I have 4 databases which have the same structure and almost same data. I want to merge them without any duplicate entry while preserving (or re-linking) the foreign keys.
For example there is a db1.product table which is almost the same as db2.products so I think I would have to use LIKE comparison on name and description columns to be sure that I only insert new rows. But then, when merging the orders table I have to make sure that the productID still indicates the right product.
So I thought of 2 solutions :
Either I use for each table insert into db1.x as select * from db2.x and then make new links and check for duplicate using triggers.
Either I delete duplicate entries and update new foreign keys (after having dropped constraints) and then insert row into the main database.
Just heard of MySQL Data Compare and Toad for mySQL, could they help me to merge tables ?
Could someone indicate to me what should be the right solution ?
sorry for my english and thank you !
First thing is how are you determining whether products are the same? You mentioned LIKE comparison on name and description. You need to establish a rule what says that product is one and the same in your db1, db2 and so on.
However, let's assume that product's name and description are the attributes that define it.
ALTER TABLE products ADD UNIQUE('name', 'description');
Run this on all of your databases.
After you've done that, select one of the databases you wish to import into and run the following query:
INSERT IGNORE INTO db1.products SELECT * FROM db2.products;
Repeat for the remaining databases.
Naturally, this all fails if you can't determine how you're going to compare the products.
Note: never use reserved words for your column names such as word "name".
Firstly, good luck with this - sounds like a tricky job.
Secondly, I wouldn't do this with PHP - I'd write SQL to do the work, assuming this is a one-off migration task and not a recurring task.
As an approach, I would do the following.
Create a database with the schema you want - it sounds like each of your 4 databases have small variations in the schema. Just create the schema for now, don't worry about the data.
Create a "working" database, with the same schema, but with columns for "old" primary keys. For instance:
table ORDER
order_id int primary key auto increment
old_order_id int not null
...other columns...
table ORDER_LINE
order_line_id int primary key auto increment
old_order_line_id int not null
order_id int foreign key
...other columns...
Table by table, Insert into your working database from your first source database. Let the primary keys auto_increment, but put the original primary key into the "old_" column.
For instance:
insert into workingdb.orders
select null, order_id, ....other columns...
from db1.orders
Where you have a foreign key, populate it by finding the record in the old_ column.
For instance:
insert into workingdb.order_line
select null, ol.order_line_id, o.order_id
from db1.order_line ol,
workingdb.order
where ol.order_id = o.old_order_id
Rinse and repeat for the other databases.
Finally, copy the data from your working database into the "proper" database. This is optional - it may help to retain the old IDs for lookups etc.
I have to insert data into two tables, Items and Class_Items. (A third table, Classes is related here, but is not being inserted into).
The primary key of Items is Item_ID, and it's an auto-incrementing integer. Aside from this primary key, there are no unique fields in Items. I need to know what the Item_ID is to match it to Classes in Class_Items.
This is all being done through a PHP interface. I'm wondering what the best way is to insert Items, and then match their Item_ID's into Class_Items. Here are the two main options I see:
INSERT each Item, then use mysql_insert_id() to get its Item_ID for the Class_Items INSERT query. This means one query for every Item (thousands of queries in total).
Get the next Autoincrement ID, then LOCK the Class_Items table so that I can just keep adding to an $item_id variable. This would mean just two queries (one for the Items, one for the Class_Items)
Which way is best and why? Also, if you have an unlisted alternative I'm open to whatever is most efficient.
The most efficient is probably going to be to use parameterized queries. That would require using the mysqli functions, but if you're to the point of needing to optimize this kind of query you should think about being there anyway.
No matter how you cut it, you've got two inserts to make. Doing the first, grabbing the new ID value as you've described (which imposes insignificant overhead, because the value is on hand to mysql already,) and using it in the second insert is pretty minimal.
I would investigate using stored procedures and/or transactions to make sure nothing bad happens.
I'm working on a project with mysql and what I did is the following (without using autoincrement fields):
1- I created a table called SEQUENCE with one field of type BIGINT called VALUE with an initial value of 1. This table will store the id value that will be incremented each time you insert a new record.
2- Create a store procedure and handle the id increment inside it within a transaction.
Here is an example.
CREATE PROCEDURE `SP_registerUser`(
IN _username VARCHAR(40),
IN _password VARCHAR(40),
)
BEGIN
DECLARE seq_user BIGINT;
START TRANSACTION;
#Validate that user does not exist etc..........
#Register the user
SELECT value FROM SEQUENCE INTO seq_user;
UPDATE SECUENCE SET value = value + 1;
INSERT INTO users VALUES(seq_user, _username, SHA1(_password));
INSERT INTO user_info VALUES(seq_user, UTC_TIMESTAMP());
COMMIT;
END //
In my case I want to store the user id in two different tables (users and user_info)