I have a column called views in my table A. I want to increment the views column like so:
UPDATE A set views = views + 1 WHERE ID = blabla LIMIT 1;
This seems like the way to do it, at least to me.
Or so I thought.
Seems like when I (from PHP) do:
$views = get_viewcount($id);
$views++:
save_viewcount($id, $views); //here we just update views with the $views variable
This always works. But carries the penalty of an extra roundtrip to the DB with the get_viewcount and then incrementing it in PHP and sending it back. It always works.
The SQL statement above "sometimes" works. I know - I too hate the word "sometimes" in programming - but put another way, I cannot say WHEN but at times it doesn't increment it when I do it in SQL directly in one go.
Suggestions?
You need to isolate the bug in your system. It is very unlikely to be a problem with MySQL.
I would suggest running a ton of tests, and looking at database logs, etc. It is most likely the query is simply not getting executed due to some logic in your system, or due to the request dying/ending before it reaches the query.
You must be doing something wrong.
If you tell mysql:
UPDATE foo SET views = views+1 WHERE id = 1337;
it will increment it.
Try it on the command line.
Whatever code you're using to run the sql is failing, not the sql statement itself.
And what's the point of LIMIT=1 on an UPDATE query?
What I recommend doing is to set PHP to echo out the query it's running, the result it's getting back, etc., etc. Everything you possibly can. Look at SQL logs if applicable to see what queries are being run on what tables. Basically you need to see exactly where the fail point it.
When you state that the SQL statement sometimes works, is that on a basis of being called from your code, or being called via a mysql (assuming that is what you are using) prompt? If it's the prior, have you tried running it in a command prompt to see if you get the same result as your code? If not, then you can rule out the database and start looking specifically at your code.
Good luck!
I would look at where and when you do your BEGIN TRANSACTION / COMMIT processing.
It could be you are not checking the SQL return code and missing a "DEADLOCK" warning.
Related
This is something I have been trying to figure out for a bit, it is the most simplest of queries that does not seem to want to work for me (only in php mysqli, works in console sql)
First I am using a prepared statement, merely looking for a match on a specialized id (from another service) to update the relation to use my primary key for easier searching on my end.
The query is as follows:
$query = "SELECT id
FROM {$this->config->dbprefix}{$table}
WHERE sf_id = ?
LIMIT 1";
I use this as one line, I split it up for better readability here
I then check that the prepare statement is valid (I do this in multiple places and it works everywhere else.
if(!($ret = $this->dbo->prepare($query))){
//handle error, this part is never called
}else{
//everything is fine, code in here is below
}
Up to here everything seems fine. Checking table and prefix manually shows they are working and referencing the proper table.
$ret->bind_param('s',$id);
$ret->execute();
$ret->bind_result($retId);
$ret->fetch();
$count = $ret->num_rows;
The problem is here, the query always returns 0 for the num_rows. Checking the query manually and trying it in console returns 1 result as it should. So far with it being such a simple query I just cannot wrap my head around why it would work elsewhere, but not here. I am sure this is the proper way to build it (I have many other queries structured similar).
Is there any kind of confusion I may be experiencing? Something easy to miss that could cause a query like this to not return results?
EDIT:
I have attempted further error handling, and trying an if test on execute does not trigger an error, though I will try more.
To expand I have a raw output of the $query variable and the id variable. By combining them and manually attempting the query in console I get the proper result. My thoughts are on somehow the prepare statement is escaping, causing the string variable $id to not properly match. Though that is just speculation.
You need to call store_result() before trying to access num_rows. Without it, the statement handle does not know how many rows are in the result set.
$ret->bind_param('s',$id);
$ret->execute();
$ret->bind_result($retId);
$ret->store_result();
$count = $ret->num_rows;
// perhaps add error handling based on number of rows here
$ret->fetch();
Basically I'm looking to create a page using PHP that will take SQL input, and output the results returned by the DB (MySQL). This is not for a production website (I understand the security implications). It's more for learning and practice. Kind of like the SQL console section of phpMyAdmin, or even similar to what sqlzoo.net can do (I think they are using perl, but I'd like to do it in PHP). Is there a practical way to accomplish this?
For example, how can I create a page in PHP/HTML to display a table of results when I don't know how many columns the query will return?
Also, what is the most practical way to allow a visitor to this web page to restore the DB to a default state with the original data? (e.g. create a sql dump of the original state and make a button that runs it? or is there a better way?)
Thanks!
Use * in your SQL query to fetch all columns and loop over the results from mysql_fetch_row() or mysql_fetch_assoc() with foreach.
Besides that, have you thought of using the mysql CLI ? It's useful for those requirements.
This question should be more specific than it is now.
"create a sql dump of the original state and make a button that runs it?" - Yes. But make sure you drop/delete the existing data.
You may have to run at least two queries... first return one row using LIMIT 1, and count the returning elements (using PHP count($row) if you use mysql $row = fetch_row($handle) ) to count the columns, and you can use SQL COUNT() to find out how many rows would be returned.
As for returning data to original state, I think a drop/recreation from a dump like you said may be the simplest and most reliable option.
Your best option is just running the query, checking if the amount of rows > 0, and then if it is, loop through the query resultset in a foreach and just show whatever you like.
I am working with a legacy PHP framework and am coming across some strange behavior that I can't track down.
I'm running a query that looks something like this
select * from table where column like '%word-anotherword%'
, which I would like to return records from table where column contains the text "word-anotherword". (column is a longtext field).
When I run this query in phpMyAdmin, I get the expected results. But when I run it from inside our framework, I get no results. I have run it in a separate .php file, using mysql_link, mysql_query to run the query, and that also behaves as expected.
When I echo out the query in the framework directly before it is passed to mysql_query, it is formatted just the same as I expect. I.E. our framework is not escaping it in some unexpected manner.
I am assuming that our framework is overriding some PHP setting somewhere to cause this difference in behavior, but I have had no luck googling for what it might be. I found this article, which seemed to be a good start, but also didn't quite seem to fit what I'm seeing, since I am getting different behaviors on the same MySQL setup.
Any pointers in the right direction would be greatly appreciated!
As a debugging heads-up:
When you echo your query out, you might want to make sure you're actually seeing the data - e.g. if you're echo-ing onto a webpage, make sure you're applying htmlspecialchars() to the string. Otherwise you might not spot some changes.
LIKE is not full text search, that's why question title is wrong and, probably, that article which you found isn't related to your problem.
And about your problem, open your my.cnf and enable queries log:
[mysqld]
#Set General Log
log = "C:/all_queries.log"
Now run your query and look into log.
I have a mysql database. What I'd like to do is perform an arbitrary action on it, and then figure out what changed. Something like this:
//assume connection to db already established
before();//saves db state
perform_action();//does stuff to db
diff();//prints what happened
I'd want it to output something like:
Row added in table_0 ]details]
Row added in table_1 [details]
Row modified in table_5 [details]
Row deleted in table_2 [details]
Any ideas?
To further clarify: You know how on stackoverflow, if you check a post's edits, you can see red lines/green highlights indicating what's been changed? I want something like that, but for mysql databases.
Instead of copying your whole database in order to save the state for a later diff, you might be better off by using triggers:
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
When you setup appropriate triggers, you can log changes to a table - for example, you can setup a trigger that automatically logs the old values and the new values for every update. To see the changes, query the table that was filled by the trigger.
Of course, the trigger is not restricted to changes made by your application, it will also log updates done by other applications. But this is also the case if you diff the old version of the database with the new version of the database.
I think normally your application would log any interesting changes as it makes them. Or you would set up history tables for everything with datetimes.
To do it the way you describe, you could dump the contents of the database into a file before and after your action and do a diff on the two files. In php, you can check out xdiff: http://us.php.net/manual/en/book.xdiff.php
If this is something you're doing only occasionally in controlled circumstances to test some queries you're not sure about, you can dump and diff on the command line.
One way is to parse the log files, which will give you exact SQL statements executed in your database. I'm not exactly sure how to separate SQL statements made by your application from other applications (if thats the case)
The only thing I can think of is to do some combination of a few somewhat hackey things:
Save a [temporary?] table of row IDs, to check for new rows. If you need to know what was in deleted or modified rows before, you'll need to copy the whole DB, which would be rather messy.
Have each row have a datestamp that gets modified on update; grab rows for whom the updated datestamp is newer than when the analysis started.
Have a layer between your application and the database (if you have something like the classic $db->query(), it would make this easy), log queries sent, which can then be looked at.
I suppose the real question is if you want to know what queries are being executed against the DB, or if you want to know what they queries you're running are actually doing.
I have a mysql trigger that logs every time a specific table is updated.
Is there a way to also log WHICH PHP SCRIPT triggered it? (without modifying each php script of course, that would defeat my purpose)
Also, is there a way to log what was the SQL statement right before the UPDATE that triggered it?
Thanks
Nathan
Short answers: no and no. Sorry.
What are you trying to achieve? Perhaps there's another way....
no, but you can get some more specific direction.
first, if you're using persitent connections, turn them off. this will make your logs easier to use.
second, since it sounds like you have multiple code bases accessing the same database, create a different user for each code base with exactly the same rights and make each code base log in with a different user. now when you look at the log, you can see which application is doing what.
third, if you have the query log on, then the UPDATE immediately preceding the trigger will be the UPDATE that caused the trigger.
fourth, if your apps use any sort of encapsulation for the mysql connection, it should be trivial to modify it to write the call stack at the time a query is sent to the database to a file.
I've read through a few of the answers and the comments. I had one idea that would be usefuls only if your queries are passing through a single point. For example, if you have a database class that all queries are executed through.
If that is the case, you could possibly add a comment to the query itself. The comment would include the function call trace, and would be added to the query as an SQL comment.
Next, you would turn query logging on and be able to see where each query is getting called from in the log file.
If your queries do not pass through a single point, you may be out of luck.
One final suggestion would be to take a look at MySQL Proxy. I have not used it much but it is designed to do intermediate processing of queries. However, I still think you would need to modify your PHP scripts to pass additional information.