According to http://us3.php.net/manual/en/pdostatement.rowcount.php:
PDOStatement::rowCount() returns the number of rows affected by the
last DELETE, INSERT, or UPDATE statement executed by the corresponding
PDOStatement object.
Using a single query, is it possible to tell if an individual JOIN'd table was affected? For instance, given the following query, how would I know if t1 was affected and if t2 was affected?
$sql ='UPDATE t1 INNER JOIN t2 ON t2.t1_id=t1.id SET t1.foo=:foo, t2.bar=:bar WHERE t2.id=:id';
$stmt = db::db()->prepare($sql);
$stmt->execute(array('foo'=>123,'bar'=>321,'id'=>10));
$rows_t1=$stmt->rowCount();
$rows_t2=$stmt->rowCount();
The UPDATE_TIME column in the information_schema.tables table approximately answers the question "which table was updated". Basic example:
SELECT UPDATE_TIME
FROM information_schema.tables
WHERE TABLE_SCHEMA = 'database' AND TABLE_NAME = 'table'
If you were to run this right after your modifying statements, you could limit to a window of a few seconds to check if a particular table was updated, like:
SELECT COUNT(*)
FROM information_schema.tables
WHERE TABLE_SCHEMA = 'database' AND TABLE_NAME = 'table'
AND UPDATE_TIME BETWEEN (NOW() - INTERVAL 30 SECOND) AND NOW();
which returns 1 if that table was updated in the last 30 seconds, or 0 if not.
I stress this is an approximate answer, because a query other than the one you last executed might have affected that table. If you were to wrap this in a transaction or a lock, then you could use this to actually answer your question: with the cost of write-locking other connections.
INNER JOIN ensures you only get results if a match is found on both tables.
Which means if the database can not match a result in one of the tables then the row is not included in the result set.
So the number of results returned from stmt->rowCount(); will reflect updates only on both tables.
Related
I want to count total records in the table. My table contains 1 million records, so I'm using
EXPLAIN
SELECT COUNT(id) FROM table_name
instead of
SELECT COUNT(id) FROM table_name
for faster retrieval.
If I'm using SELECT COUNT(id) FROM table_name means I'm getting proper count. EXPLAIN SELECT COUNT(id) FROM table_name gives wrong count. I have reduced the record count to 10000, But still I can't find the issue.
Here is my Query
EXPLAIN SELECT COUNT(id) FROM table_name - 12764 - wrong
SELECT COUNT(id) FROM table_name - 10000 - right
Explain is not an optimization it is a description of the execution plan for the specified statement. This explanation is returned as a table. And this is what you are counting.
Therefore you are counting completely different things.
From the MySQL docs:
EXPLAIN is used to obtain a query execution plan (that is, an explanation of how MySQL would execute a query).
As explain select can return the rows affected. You may want to use something like
EXPLAIN
SELECT SUM(rows)
FROM table_name
GROUP BY (table, rows)
I have a table that has been functional and i added a column to the table. After adding the column i want to add the result of a query (query is same for all but different results) into that column all at once instead of one at a time which will be time consuming. How can i achieve that? Cos after updating, i have just one result in all the column, i cannot use a where clause cos it will require me doing it one after the other
$stmt = $pdo->prepare("UPDATE table SET my_value = '$myValue' ");
$stmt->execute();
UPDATE table
SET my_value = (select col from some_table where ...)
If the value is the same for all rows, I would advise using cross join:
update table t cross join
(select newval . . .) x
set t.col = x.newval;
Note: this is better than a subquery, because the subquery is guaranteed to be evaluated only once.
If you are trying to say that the value is the same for groups of columns, then extend this to a join:
update table t join
(select grp, newval . . .) x
on t.grp = x.grp
set t.col = x.newval;
After adding the column I want to add the result of a query (query
result is same for all) into that column all at once instead of one at
a time which will be time consuming.
The solution depends on what you mean by "Is the same for all the rows."
If you have one value that is exactly the same for all columns, you can just ask for it and then update. This is usually faster (and allows you to debug more easily) than using pure SQL to achieve everything.
If, on the other hand, you mean the values of that column are retrieved by the same query, but will be different for different rows, then a subquery or a cross join as Gordon suggested will do the trick.
$res = $db->query("SELECT COUNT(*) as cnt FROM table")->fetchAll(PDO::FETCH_ASSOC);
if ( $res[0]['cnt'] == 0 ) {
$db->query("
INSERT INTO table (col)
VALUES
('value1'),
('value2'),
('value3'),
....
");
}
Suppose 2 users requested this code same time,
So, for first user, count will return 0 and INSERT query will executed, but there is possible that while first insert executed, for second user, count return also 0 ? (and in this case second insert query will also executed, what I don't need).
If this is possible, how to prevent this? Using Transactions will help in such cases ?
So, you want to insert only if there are no records in the table. Transactions won't help you.
You can use a WRITE LOCK:
Only the session that holds the lock can access the table. No other session can access it until the lock is released.
https://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
Use the following method:
mysql> LOCK TABLES t1 WRITE;
mysql> SELECT COUNT(*) FROM t1;
mysql> INSERT INTO t1 (col)
VALUES
('value1'),
('value2'),
('value3');
mysql> UNLOCK TABLES;
If another session tries to execute the command LOCK TABLES t1 WRITE;, it will wait until the first session finishes. So COUNT will always return the correct value.
Getting the number of rows affected by a MySQL update is one thing, but how do I get the number of matching rows for an UPDATE query? Otherwise put, the number of rows that COULD have been affected by the update query, even if the data I'm trying to update the rows with is identical to the data already contained within them? Because in this specific case, the DB will not overwrite the data with, so the number of affected rows is 0.
Is there some PDO method that helps, similar to PDOStatement::rowCount() ?
I also want to avoid a secondary SQL statement, otherwise the question is pointless.
You can use count() in a select clause for that:
If your update statement would be
update your_table
set some_column = 'hello'
where id = 1
Then you could select the affected rows count like this
select count(*) as affected_rows
from your_table
where id = 1
I wanted to avoid extra queries if possible and fortunately, a colleague of mine pointed out that I can give the PDO instance a particular MySQL driver option that forces the rowCount method to return the number of matches related to the query, instead of the number of affected rows, like so:
$options = array(
PDO::MYSQL_ATTR_FOUND_ROWS => true // forces the rowCount() method to return the number of matching rows, not the number of affected rows
);
$connection = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass, $options);
Here is another way:
mysql_query('begin');
mysql_query('update ...');
mysql_affected_rows();
mysql_query('rollback');
select count(*) is a better thing to do for simple queries. But that won't get correct results in case you are updating multiple tables with joins.
Add the column update_time in model.Whenever update model.Automatically save updated time in that field.
And
How about querying like this
SELECT * from
table_name
WHERE 'updated_time=12:05:23'
I have an sql query that simply adds a row to an existing database table. The first field is id and I assume this value has to be specified in the query.
So then id has to be the number of rows existing + 1. I'm determining the id like this:
SELECT COUNT(1) FROM testtable
The problem is that this returns the number of rows that have ever been added, including deleted ones. Because I have been adding and removing from this table, this number is greater than the number of EXISTING rows in the table which is what I want.
How can I count the existing rows in the table instead of the existing + deleted rows?
If possible switch to using an auto_increment column for your id and don't be concerned with gaps in the sequence of ids. Your own implementation of id generation may inflict more harm especially in a long run.
Now, back to your immediate question. You are probably looking for this
SELECT MAX(id) + 1 new_id
FROM Table1
Note: This query might fail under heavy load when several concurrent sessions issuing this
query might grab the same id and your subsequent INSERT will fail. Therefore again consider using an auto_increment for your id.
Here is SQLFiddle demo
That's a bad idea, because you can end up with duplicate IDs, especially if you delete rows in the middle. If you're not going to use an auto-increment field, you can add the ID to the insert. Just use this in place of the value:
((SELECT MAX(t.id) + 1 FROM table t)
The full query would then be:
INSERT INTO table_name (id, col1, col2, col3) VALUES ((SELECT MAX(t.id) + 1 FROM table_name t), :col1, :col2, :col3)
SELECT COUNT(*) from table
will return only the number of entries in it, not based on the ID
There is also possibility to find, and fill the gaps, by picking first free id
SELECT MIN(t1.id + 1) AS free_id
FROM t1
WHERE NOT EXISTS (SELECT t2.id FROM t2 WHERE t2.id = t1.id + 1)