I want to get the last affected table name (after insert).
I tried with mysql_insert_id() but i got only id.
I want table name also.
Can anyone give me the idea for my problem
It's a strech... But if :
you are running mysql 5.6.3 +
you still have access to the insert query (let's say it's $query)
you are sure it's an insert query (because, hey, you know you want last_insert_*, don't you?)
You can try:
$row = mysql_fetch_assoc(mysql_query("explain $query"));
$table = $row['table'];
From mysql 5.6.3+ you can combine explain with a insert into query.
This should return only 1 row, I think.
I dont have mysql 5.6.3+ myself to test it.
You can override mysql_query function as defined in this post, save you last call table name in global var or session and pray for last called insert finish last.
// THIS JUST SAMPLE... use code from link below ^
function custom_mysql_query($query){
if(strstr('INSERT',$query)){
/*GET YOUR TABLE NAME WITH REGEX*/
}
basic_mysql_query($query);
}
This is very very very bad solution for me. But in theory will work.
You mention in your comment that you're using a common function to apply the changes in, preventing you from 'knowing' what the last table is you inserted in.
If that's the case: your logic is flawed.
MySQL is not gonna tell you what the last table is it did an INSERT in. You will have to write a hook in your function where you last know what table you're gonna update. No matter what function you use, you must specifiy a table name at some point, before executing the insert. You store the table name at that point.
You can do that in many ways, depending on your needs:
store it in a mysql table (last_updated_table with only 1 column,
for example)
store it in a variable (if you only need it in the
same request)
store it in a session (I wouldn't opt for this)
You can use the information_schema database if you have one :
SELECT TABLE_SCHEMA, TABLE_NAME, UPDATE_TIME
FROM TABLES
ORDER BY UPDATE_TIME DESC
LIMIT 0,1
Use this after your query, and you'll get the affected table.
Related
I have the following call to my database to retrieve the last row ID from an AUTO_INCREMENT column, which I use to find the next row ID:
$result = $mysqli->query("SELECT articleid FROM article WHERE articleid=(SELECT MAX(articleid) FROM article)");
$row = $result->fetch_assoc();
$last_article_id = $row["articleid"];
$last_article_id = $last_article_id + 1;
$result->close();
I then use $last_article_id as part of a filename system.
This is working perfectly....until I delete a row meaning the call retrieves an ID further down the order than the one I want.
A example would be:
ID
0
1
2
3
4-(deleted row)
5-(deleted row)
6-(next ID to be used for INSERT call)
I'd like the filename to be something like 6-0.jpg, however the filename ends up being 4-0.jpg as it targets ID 3 + 1 etc...etc...
Any thoughts on how I get the next MySQL row ID when any number of previous rows have been deleted??
You are making a significant error by trying to predict the next auto-increment value. You do not have a choice, if you want your system to scale... you have to either insert the row first, or rename the file later.
This is a classic oversight I see developers make -- you are coding this as if there would only ever be a single user on your site. It is extremely likely that at some point two articles will be created at almost the same time. Both queries will "predict" the same id, both will use the same filename, and one of the files will disappear, one of the table entries may point to the wrong file, and the other entry will reference a file that does not exist. And you'll be scratching your head asking "how did this happen?!"
Predicting auto-increment values is bad practice. Don't do it. Plan for concurrency.
Also, the information_schema tables are not really tables... they are server internals exposed to the SQL interface. Calls to the "tables" table, and show table status are expensive calls that you do not want to make in production... so don't be tempted to use something you find there.
You can use mysql_insert_id() after you insert the new row to retrieve the new key:
$mysqli->query($yourQueryHere);
$newId = $mysqli->insert_id();
That requires the id field to be a primary key, though (I believe).
As for the filename, you could store it in a variable, then do the query, then change the name and then write the file.
Let's say you're making a CodeIgniter model's function which creates a user.
function create($data){
$sql = "INSERT INTO people (fname,lname,age,location) VALUES(?,?,?,?)";
$this->db->query($sql, $data);
}
function get($id){
$sql = "SELECT * FROM people WHERE id = ? LIMIT 1";
return $this->db->query($sql, array($id));
}
You want create() to create the user but return the same thing as get() as an associative array containing the user id and the other inserted info.
Obviously this could be done by making an array containing the $data elements. But think about a lot of fields.. it makes the code ugly and unsecure to modify because you'll deal with numerical arrays not associative.
Is there any way for the MySQL to return the inserted record with the id without having to query again using SELECT for better performance and neat looking code?
You can't insert and return the row in the same query with MySQL.
But you can get the last inserted id (I'm guessing the id field is autogenerated) with ->insert_id. You can use that to call get from your create function.
you could wrap the whole thing (INSERT plus SELECT) in a procedure, which would save you a callout to the database, and at the same time ensuring you read exactly what exists in the database (for e.g. autoincrement columns or defaulted values). But procedures aren't everybody's cup of tea.
In MySQL, no, there's no way to do what you want. Some databases (at least PostgreSQL) support a INSERT ... RETURNING syntax, which allows this. Unfortunately, you will either have to re-query the newly inserted row, or mangle a return value out of the input value in your client code.
As #Flimzy said you cannot do it in one query ala Postgres with its RETURNING clause.
Your best bet is to use MySQL's LAST_INSERT_ID() which is guaranteed to return the newly created record's ID and its scoped to the current session so there is no issue of getting a race condition
I have two tables called clients, they are exactly the same but within two different db's. Now the master always needs to update with the secondary one. And all data should always be the same, the script runs once per day. What would be the best to accomplish this.
I had the following solution but I think maybe theres a better way to do this
$sql = "SELECT * FROM client";
$res = mysql_query($conn,$sql);
while($row = mysql_fetch_object($res)){
$sql = "SELECT count(*) FROM clients WHERE id={$row->id}";
$res1 = mysql_query($connSecond,$sql);
if(mysql_num_rows($res1) > 0){
//Update second table
}else{
//Insert into second table
}
}
and then I need a solution to delete all old data in second table thats not in master.
Any advise help would be appreaciated
This is by no means an answer to your php code, but you should take a look # Mysql Triggers, you should be able to create triggers (on updates / inserts / deletes) and have a trigger (like a stored proceedure) update your table.
Going off the description you give, I would create a trigger that would check for changes to the 2ndary table, then write that change to the primary table, and delete that initial entry (if so required) form the 2ndary table.
Triggers are run per conditions that you define.
Hopefully this gives you insight into 'another' way of doing this task.
More references on triggers for mysql:
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
http://www.mysqltutorial.org/create-the-first-trigger-in-mysql.aspx
You can use mysql INSERT ... SELECT like this (but first truncate the target table):
TRUNCATE TABLE database2.client;
INSERT INTO database2.client SELECT * FROM database1.client;
It will be way faster than doing it by PHP.
And to your notice:
As long as the mysql user has been given the right permissions to all databases and tables where data is pulled from or pushed to, this will work. Though the mysql_select_db function selects one database, the mysql statement may reference another if you use complete reference like databasename.tablename
Not exactly answering your question, but how about just using 1 table, instead of 2? You could use a fedarated table to access the other (if it's on a different mysql instance) or reference the table directly (like shamittomar's suggestion)
If both are on the same MySQL instance, you could easily use a view:
CREATE VIEW database2.client SELECT * FROM database1.client;
And that's it! No synchronizing, no cron jobs, no voodoo :)
I am having a wee problem, and I am sure there is a more convenient/simpler way to achieve the solution, but all searches are throw in up a blanks at the moment !
I have a mysql db that is regularly updated by php page [ via a cron job ] this adds or deletes entries as appropriate.
My issue is that I also need to check if any details [ie the phone number or similar] for the entry have changed, but doing this at every call is not possible [ not only does is seem to me to be overkill, but I am restricted by a 3rd party api call limit] Plus this is not critical info.
So I was thinking it might be best to just check one entry per page call, and iterate through the rows/entires with each successive page call.
What would be the best way of doing this, ie keeping track of which entry/row in the table that the should be checked next?
I have 2 ideas of how to implement this:
1 ) The id of current row could be save to a file on the server [ surely not the best way]
2) an extra boolean field [check] is add to the table, set to True on the first entry and false to all other.
Then on each page call it;
finds 'where check = TRUE'
runs the update check on this row,
'set check = FALSE'
'set [the next row] check = TRUE'
Si this the best way to do this, or does anyone have any better sugestion ?
thanks in advance !
.k
PS sorry about the title
Not sure if this is a good solution, but if I have to make nightly massive updates, I'll write the updates to a new blank table, then do a SQL select to join the tables and tell me where they are different, then do another SQL UPDATE like
UPDATE table, temptable
SET table.col1=temptable.col1, table.col2=temptable.col2 ......
WHERE table.id = temptable.id;
You can store the timestamp that a row is updated implicitly using ON UPDATE CURRENT_TIMESTAMP [http://dev.mysql.com/doc/refman/5.0/en/timestamp.html] or explicitly in your update SQL. Then all you need to do is select the row(s) with the lowest timestamp (using ORDER BY and LIMIT) and you have the next row to process. So long as you ensure that the timestamp is updated each time.
e.g. Say you used the field last_polled_on TIMESTAMP to store the time you polled a row.
Your insert looks like:
INSERT INTO table (..., last_polled_on) VALUES (..., NOW());
Your update looks like:
UPDATE table SET ..., last_polled_on = NOW() WHERE ...;
And your select for the next row to poll looks like:
SELECT ... FROM table ORDER BY last_polled_on LIMIT 1;
I have a MySQL query that goes as follows (using Zend_Db):
$sql = $handle->quoteInto("UPDATE board SET rank=rank+1 WHERE post_id=?", $postid);
$handle->query($sql);
(Rank isn't an auto-incrementing PK).
I would like to now retrieve the value of rank without preforming another query.
I've tried $handle->lastInsertId(); but it doesn't seem to work , since I didn't use MySQL's natural auto-incrementing method (I can't - rank is the rank of a post. I either ++ or -- it.)
Any way to do this with preforming another query? A function that will return the last changed value?
I don't believe this is possible - you'll just have to do a SELECT.
You can use the LAST_INSERT_ID function that MySQL provides to set a value and then make it available via the mysql_insert_id() C function that the $handle->lastInsertId(); relies on.
The following is an updated version of your code snippet with the LAST_INSERT_ID changes made to it:
$sql = $handle->quoteInto("UPDATE board SET rank=LAST_INSERT_ID(rank+1) WHERE post_id=?", $postid);
$handle->query($sql);
Let me know if you have any questions.
HTH,
-Dipin