I have an SQL table with an auto-increment field. I know people have asked how to retrieve the ID of the 'last entry' after the insert has taken place, and I know how to do that. What I want to do is duplicate the auto-generated field in to a second column of the same table - how do I modify my insert code to do this:
mysql_query("INSERT INTO `tags` (`tid`,`tagid`,`tagname`) VALUES('','INSERTED.ID','{$tagname}')");
The reason I want to do this is because I want to be able to make two rows equal each other. I.E. if two different tags (with different unique ids) have the same tagid, then I can use the 'tagid' reference elsewhere as a unique identifier and cycle through them. I can also retain knowledge of which tag is the parent tag - because it will have the same 'tid' as 'tagid'.
I have a system for tagging events; but sometimes I miss-spell a tag... so rather than correcting all the mistakes, I want to make my system error proof by allowing miss-spelt tags to be joined up and treated the same way as a the correct tag.
Would appreciate your help - even if that means doing this a completely different way.
Thanks,
2 options:
1) You can use LAST_INSERT_ID() mysql function, but in a second query, not in the same.
SELECT LAST_INSERT_ID();
2) Define a insert Trigger in the table, then when you insert, the trigger "triggers" and do the action in the trigger.
CREATE TRIGGER tag_tid BEFORE INSERT ON tags
FOR EACH ROW NEW.tid = NEW.id;
Note: Short creator, see more in the link.
you have to alter the table to set the field to autoincrement. And then I believe when you insert anything it increments. There is also this statement called on duplicate...http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
You could store the previous id, and then use it in your query string.
$previous_id = mysql_insert_id();
mysql_query("INSERT INTO `tags` (`tid`,`tagid`,`tagname`) VALUES('','$previous_id','{$tagname}')");
Related
I have a table with 4 column (id, name, surname, tel)
id is primary key
name, surname and tel are unique.
Now i have to insert a row and if there is already a row with that name-surname-tel take the id and return it otherwise insert normally.
I thinked at 2 strategy:
1) do a select before insert, if nothing is found insert it otherwise take the id
2) try to insert, if the error code 1 (unique constraint violated) happen do the select and take the id
which one is better? or there is another strategy i can do by php?
You are correct, those are the best options. The differences are minimal if any in terms of performance.
If you do the first one, you still have to implement the second also. Because between your first SELECT request and your second INSERT statement, another process could have altered the database, unless you do it in a single transaction.
You could turn it into a SELECT INTO statement to have the insert/check in a single query, but then you still have to do a second SELECT to get the ID.
So in conclusion: I would go for the second option where you insert and check for the error.
Can this be done in a single query? The table has an auto increment field which I need to know the number to fill url field in the table.
Table
id(AI) | title | url
What I am expecting is something like
INSERT INTO table (title,url) VALUES ('name','CONCATENATION OF title AND ID');
I am currently doing this using 2 queries.
1.Writing the fields except URL.
Getting the id using mysqli_insert_id()
2.Updating the above written row.
P.S : The Table has other fields as well so changing the db design isnt really possible in this case.
It can't be done atomically. In theory, you could SELECT MAX(id) + 1 FROM yourtable, but please, please don't - although this is not guaranteed to give you the right result and is definitely not a safe approach.
This seems like bad practice, anyway. Why not concatenate the title and ID when you fetch it? Why must it be concatenated on insert?
I will not comment on the design of your database -- you are the judge of that. Just bear in mind that the following command gets the next auto-increment-ID for the specified table, and that this number could change in an instant if another user accesses the table before your code can use it.
I am using this code myself in a project for a similar reason to your own, and it works for me because the table is updated only a few times per day and never by more than one person at a time.
SELECT Auto_increment FROM information_schema.tables WHERE
table_name = '$name_of_your_table';
To be clear, this code gets the auto-increment ID that will be given to the next table entry for the specified table.
Although some major systems like Joomla store tags as comma-separated text in the main article database, normalized system of three tables as article, tags and tag-relationship is preferred (as others like Wordpress uses). There are lots of discussions and questions about structure and reading; but I was unable to find the best INSERT command, as we need to insert into three tables. How to quickly run this process through one SQL run? Or we need to first insert article, then each tags, and finally writing the relationships?
Another question is about the uniqueness of the tags. The main advantage of this system is that we only need to store each term only once (then connecting to corresponding articles). Is it practical to use mysql UNIQUE to avoid duplication? Or (as I read somewhere) we need to read the entire list of tags as an array to find any duplication to catch the tag ID and avoid storing the term?
Will the whole process as three individual steps:
INSERT the article
INSERT tags with UNIQUE but regardless of their relationship
Finding each tag ID and make a relationship to the article ID
Am I right? The reason that I asked is that I saw people catch the tags as an array and make a comparison. To me it is very slow, and kills the performance, particularly for UPDATE.
You can only ever insert in one table at a time.
One solution is to use triggers, the other is to use a transaction.
The first can be used with any engine, the latter requires InnoDB or alike engine.
Make sure you put a UNIQUE index on the field tag.name.
1-Using transactions
START TRANSACTION;
INSERT IGNORE INTO tag (name) VALUES ('$example1', '$example2');
INSERT INTO article (title, body) VALUES ('$title','$body');
SET #article_id = LAST_INSERT_ID();
INSERT INTO tag_link (tag_id, article_id)
SELECT t.id, #article_id FROM tag t WHERE t.name IN ('$example1','$example2');
COMMIT;
2-Using a trigger on a blackhole table
Create a table of type blackhole with the following fields.
title: varchar(255)
body: text
tag1: varchar(50) DEFAULT NULL
tag2: varchar(50) DEFAULT NULL
...
add as many tags as you want.
Add a AFTER INSERT trigger to the blackhole table to do the actual storage for you.
DELIMITER $$
CREATE TRIGGER ai_bh_newacticle_each AFTER INSERT ON bh_newacticle FOR EACH ROW
BEGIN
INSERT IGNORE INTO tag (name) VALUES (new.tag1, new.tag2,...,new.tag25);
INSERT INTO article (title, body) VALUES (new.title,new.body);
SET #article_id = LAST_INSERT_ID();
INSERT INTO tag_link (tag_id, article_id)
SELECT t.id, #article_id FROM tag t
WHERE t.name IN (new.tag1, new.tag2,...,new.tag25);
END$$
DELIMITER ;
DELIMITER $$
Now you can just insert the article with tags in a single statement:
INSERT INTO bh_newarticle (title, body, tag1, tag2, tag3)
VALUES ('$title','$body','$tag1','$tag2','$tag3');
Back to your question
Am I right? The reason that I asked is that I saw people catch the tags as an array and make a comparison. To me it is very slow, and kills the performance, particularly for UPDATE.
Tags are only useful if there are i a limited number of them. If you put a (unique) index on tag.name looking for a tag will be very fast, even with 10.000 tags. This is because you are looking for an exact match. And if you are really in a hurry you can always make the tag table a memory table with a hash index on the name field.
I doubt you need to worry about slowness in the tag lookup though.
Just make sure you don't allow too many tags per article. 5 seems a good start. 10 would be too many.
Links
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
http://dev.mysql.com/doc/refman/5.0/en/blackhole-storage-engine.html
You can't insert into 3 tables in one single statement but you can run the 3 insert statements in one transaction.
I don't see an issue with declaring the tag column as unique since you want to avoid duplication. You can always check if the tag exists or not before you insert it into the table or better yet, simply upsert the tags.
You run each INSERT by issuing a single query, there's no "workaround" nor is it even feasible for one to exists. So, 3 inserts for 3 tables.
If you need unique tags, then yes - it's good to use UNIQUE constraint to avoid duplication.
Simple INSERT IGNORE MySQL feature should do the trick to help you avoid whether the record exists or not before inserting.
there some possibilities depending on DBMS functionality i.e:
stored procedures, instead of triggers, may any other to make it possible to insert with one sql statement, but i think it does not worth it, because it not so critical even to insert in all 3 table in one transaction... it is not bad if article is saved but tags are failed to save... But, if needed, stored procedure is the best for this task, because it allows complicated logic, and you also can write subprogram in your program to exec all sql and call it when needed in 1 line...
you can create unique index on tags table on tag field and on rel table on fields (article_id, tag).
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)
How can we re-use the deleted id from any MySQL-DB table?
If I want to rollback the deleted ID , can we do it anyhow?
It may be possible by finding the lowest unused ID and forcing it, but it's terribly bad practice, mainly because of referential integrity: It could be, for example, that relationships from other tables point to a deleted record, which would not be recognizable as "deleted" any more if IDs were reused.
Bottom line: Don't do it. It's a really bad idea.
Related reading: Using auto_increment in the mySQL manual
Re your update: Even if you have a legitimate reason to do this, I don't think there is an automatic way to re-use values in an auto_increment field. If at all, you would have to find the lowest unused value (maybe using a stored procedure or an external script) and force that as the ID (if that's even possible.).
You shouldn't do it.
Don't think of it as a number at all.
It is not a number. It's unique identifier. Think of this word - unique. No record should be identified with the same id.
1.
As per your explanation provided "#Pekka, I am tracking the INsert Update and delete query..." I assume you just some how want to put your old data back to the same ID.
In that case you may consider using a delete-flag column in your table.
If the delete-flag is set for some row, you shall consider program to consider it deleted. Further you may make it available by setting the delete-flat(false).
Similar way is to move whole row to some temporary table and you can bring it back when required with the same data and ID.
Prev. idea is better though.
2.
If this is not what you meant by your explanation; and you want to delete and still use all the values of ID(auto-generated); i have a few ideas you may implement:
- Create a table (IDSTORE) for storing Deleted IDs.
- Create a trigger activated on row delete which will note the ID and store it to the table.
- While inserting take minimum ID from IDSTORE and insert it with that value. If IDSTORE is empty you can pass NULL ID to generate Auto Incremented number.
Of course if you have references / relations (FK) implemented, you manually have to look after it, as your requirement is so.
Further Read:
http://www.databasejournal.com/features/mysql/article.php/10897_2201621_3/Deleting-Duplicate-Rows-in-a-MySQL-Database.htm
Here is the my case for mysql DB:
I had menu table and the menu id was being used in content table as a foreign key. But there was no direct relation between tables (bad table design, i know but the project was done by other developer and later my client approached me to handle it). So, one day my client realised that some of the contents are not showing up. I looked at the problem and found that one of the menu is deleted from menu table, but luckily the menu id exist in cotent table. I found the menu id from content table that was deleted and run the normal insert query for menu table with same menu id along with other fields. (Id is primary key) and it worked.
insert into tbl_menu(id, col1, col2, ...) values(12, val1, val2, ...)