deleting from two tables in one query mysqli - php

I want to delete from two tables. I know I can use a join but I came across this post suggesting I could just do it like this with a semicolon:
$query = " DELETE from pupil_data WHERE pupil_id=$pupil_id;
DELETE from pupil_conditions WHERE pupil_id=$pupil_id";
$bob = $conn->query($query);
This doesn't work. If I do each query on their own then its fine.
Why doesn't it work with the semicolon?

try like this
$query = " DELETE from pupil_data WHERE pupil_id=$pupil_id;
DELETE from pupil_conditions WHERE pupil_id=$pupil_id";
$bob = $conn->multi_query($query);

First of all, your query doesn't delete from two tables in one query. There are two separate SQL queries.
Second, you don't need to run 2 queries in one function call. Run two separate queries in two separate function calls. That would be logical and save you a lot of trouble.
Third, never use mysqli_multi_query() for such a whim. This function's purpose is different. Everyone who ask you to use it, never used it in reality and have no idea how to use it properly, helping you to shoot yourself in the foot.
Fourth, you ought to use prepared statements, instead of banging a variable in the query directly.
$stmt = $conn->prepare("DELETE from pupil_data WHERE pupil_id=?");
$stmt->bind_param("s",$pupil_id);
$stmt->execute();
$stmt = $conn->prepare("DELETE from pupil_conditions WHERE pupil_id=?");
$stmt->bind_param("s",$pupil_id);
$stmt->execute();
is the code you have to run.

DELETE table_1, table_2,... FROM table-refs [WHERE conditions]
DELETE FROM table_1, table_2,... USING table-refs [WHERE conditions]
Here is the reference

Related

MySQLi multiple prepare statements

I have checked everywhere thoroughly, and have gone through everything possible to find an answer to this. Besides saying "the code doesn't work" which obviously is not enough, I have yet to find anything that will even come close to this. I'm probably going to get downvotes, but let's see how this goes.
I am learning how to do prepared statements for a search query from the user end, and I have to do it for multiple queries. I have to bind parameters to these multiple queries, and then execute them and use them and receive multiple rows. This is most of my code, and what I currently have is not reporting any errors whatsoever. It just returns a blank white page.
I am doing this from a simple test.php file, and those are the results I'm getting.
Now for the code.
$prep1 = $test->prepare("SELECT * FROM sb__bans WHERE sb__bans.authid=? ORDER BY sb__bans.bid DESC");
$prep2 = $test->prepare("SELECT * FROM sb__bans AS bans INNER JOIN sb__admins AS admins ON bans.aid = admins.aid WHERE bans.authid=? ORDER BY bans.bid DESC");
$prep3 = $test->prepare("SELECT * FROM sb__bans AS bans INNER JOIN sb__servers AS servers ON bans.sid = servers.sid WHERE bans.authid=? ORDER BY bans.bid DESC");
$search = "steam";
$prep1->bind_param("s", $search);
$prep2->bind_param("s", $search);
$prep3->bind_param("s", $search);
$prep1->execute();
$prep2->execute();
$prep3->execute();
while($row = $prep1->fetch() && $admin = $prep2->fetch() && $sv = $prep3->fetch()) {
echo $row['test'];
echo $admin['test'];
echo $sv['test'];
}
The database is initialized above this as $test = new mysqli("localhost", "test", "test", "test");
$search = "steam" steam would be replaced with the the post variable of course, but for testing reasons I've removed that for now and am testing with just a simple variable.
What seems to be the problem here?
Thanks in advance.
Regarding the general question you asked.
There is not a single problem with having multiple queries prepared. While speaking of getting results from a prepared query, there is indeed a problem caused by the result buffering. In order to be able to execute another query, you have to call store_result()/get_result() right after execute.
Regarding the particular problem you have.
To get errors you have to ask PHP for them.
There is absolutely no point in making three queries, you have to make just one. If you have a trouble making one, ask another question marking it with mysql tag and bringing your 3 queries along.
Even for multiple queries it's just wrong idea to do multiple fetches in a single loop. Fetch your query results one by one.
Your mysqli syntax even for a single query is incomplete. You need to re-read your tutorial and practice on a single query first.
Two points:
Based on personal experience, you can only have one prepared statement in existence at a time. I suspect this is because the db requires each PS to have a session-unique name, and the PHP layer is passing some common default name rather than generating a unique name for each PS. By comparison, the PostgreSQL driver allows an optional name for each PS, but still allows only one unnamed PS to exist. Essentially this means that you must prepare, bind, execute and fetch one PS completely before you can prepare the next PS.
You're misusing mysqli_stmt::fetch(). fetch() returns only true or false, and is used to update variables which have previously been bound with mysqli_stmt::bind_result(). To retrieve values into a $row array, you must first call mysqli_stmt::get_result() to return a mysqli_result, and then call mysqli_result::fetch_array().

How to share connection_id between 2 queries?

I need to execute two SQL statements together because connection_id() in the first statement will be used in the Mysql view wp_statistics_benchmarks.
Without the connection_id(), the wp_statistics_benchmarks is an empty view. The following SQL works fine and get results:
replace into wp_params (`view_name` , `param1_val`, `connection_id`)
values ('benchmarks', 484 , connection_id())
;
select * from wp_statistic_benchmarks;
But, to work with wordpress, the following code doesn't work:
$mysqli = new mysqli(.....);
$results = $this->_wpdb->query("
replace into wp_params (`view_name`, `param1_val`, `connection_id`)
values ('benchmarks', $connected_from, $mysqli->thread_id);
select * FROM `wp_statistic_benchmarks`;"
);
How can I convert these two mysql codes into Wordpress wpdb queries?
Use the wpdb object twice.
$this->_wpdb->query('replace into ...');
$rows = $this->_wpdb->get_results('select ...')
Let me put it another way, select * from wp_stat ... and replace into wp_params ... from your original "mysql codes" are separate statements without any relation to each other.
You think that you need to run them in sequence, whereas in fact you can have a cup of coffee or even travel around the earth in between those replace into and select statements and they would still do the same thing. If that is not the case, then your question lacks information necessary to provide a good answer because wp_params is not a standard table in wordpress and neither is the view. I don't think you understand your problem.
Besides, running them as I suggest is equivalent with your "mysql codes". Moreover, $wpdb->query returns the number of affected rows or false, so you will never be able to run a select statement with $wpdb->query() to retrieve a set of tuples.
How can I convert these two mysql codes into Wordpress wpdb queries?
You can't. That's because you're using wpdb and it only supports one query per ->query() call. However, if you're using Mysqli with wpdb, you can use the multi_query() method of it with wpdb. Here is how:
To use multiple queries, you need to ensure that wpdb uses Mysqli (e.g. define the USE_EXT_MYSQL constant as FALSE in your Wordpress config).
Then you can obtain the mysqli instance from the wpdb object, either with reflection or a helper class/module:
abstract class wpdb_dbh extends wpdb
{
static function from(wpdb $wpdb) {
return $wpdb->dbh;
}
}
Mysqli is then available without creating a new instance:
$mysqli = wpdb_dbh::from($this->_wpdb);
As this is a valid Mysqli instance you can run multi query.
But just obtaining the same Mysqli instance as wpdb uses it probably the most important thing here as otherwise your open an additional connection with new mysqli(...) which you need to prevent.
Additionally take care that $mysqli->thread_id is a fitting replacement to connection_id() following the same formatting/encoding. You should be able to use connection_id() directly anyway, so I actually see not much reason to access the thread_id member, but it's perhaps only because you tried some alternatives and I'm just over-cautious.
The ';' query delimiter is purely an SQL shell convenience and is not a part of the MySQL dialect so you're correct that your code doesn't work.
Here's the actual replacement code:
$mysqli = new mysqli(.....);
$this->_wpdb->query(
"replace into wp_params
(`view_name`, `param1_val`, `connection_id`)
values ('benchmarks', $connected_from, $mysqli->thread_id)");
$results = $this->_wpdb->query("select * FROM `wp_statistic_benchmarks`");
This is the same as Ярослав's answer above.
Update:
If your code is still not working you might have to enable persistent connections in Wordpress.
Update 2:
There was a missing space between in the second query's select statement and the * shorthand all columns selector. Interestingly this may or may not cause an issue for you, it doesn't seem to bother my MySQL 5.5 command line shell.
If I understand your requirements (and I do not know wordpress), you are inserting a row to wp_params with a column called connection_id. I would assume that this value will be unique on the table. I would be tempted to add an integer autoincrement id field to the table and then get the value of that (last insert id). Then use this id in a WHERE clause when selecting from the view.

Using PDO, do I really need to run two separate prepared statements to get the number of rows returned?

What is the preferred method for getting the number of rows that are returned for a SELECT state when using PDO with prepared statements?
I am currently using rowCount() but the docs say I shouldn't be using that since "most databases" don't support it (It is actually working just fine for me, so I'm tempted to keep using it. I can't find any sources that list exactly which databases do not support it, but apparently mine is fine).
Instead they recommend I use fetchColumn() but that requires writing a completely separate SQL statement that includes the COUNT(*) in my sql statement.
This is what they propose (http://php.net/manual/en/pdostatement.rowcount.php#example-1038):
//SQL TO GET ROWS TO OUTPUT
$sql = 'SELECT *
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$result = $dbh->prepare($sql);
$result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$result->execute();
//SQL TO GET NUMBER OF RETURNED ROWS
$row_num_sql = 'SELECT COUNT(*)
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$row_num_result = $dbh->prepare($row_num_sql);
$row_num_result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$row_num_result->execute();
$num_rows = $row_num_result->fetchColumn();
if($num_rows > 0) {
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'];
}
}
I find this method that requires me to write a separate and nearly identical sql statement to be redundant and a serious pain when using prepared statements. I can understand how this approach might be acceptable when using a short SQL statement with a basic query, but not in the case of a prepared statement.
1. Is there any other way I can use the fetchColumn() approach
without having to rewrite what is almost exactly the same code?
2. Where can I find an official list of which databases
rowCount() supports when using a SELECT statement? And since it is
working on the database I am currently using, can I assume it is safe
to use(assuming I am not updating my database anytime soon)?
If you don't want to use rowCount I'm think you should two query, or you can use fetchAll and count(fetchAll) for rowCount
the second way, Use SELECT *,COUNT(*) ...

Inserting multiple SQL statements in codeIgniter

I have the following SQL that works directly in MySQL
INSERT INTO `my_tabel` (`data`) VALUES ("my_value");
SELECT * from `my_tabel` ORDER BY `id` DESC LIMIT 1
It inserts a row, and then gets the new row so that I can return the new ID to use later.
When I try to run the SQL in codeIgniter I get an error message stating that I have an error in my SQL
$m = new my_model();
$sql = 'INSERT INTO `my_tabel` (`data`) VALUES ("'.$my_value.'"); SELECT * from `my_tabel` ORDER BY `id` DESC LIMIT 1';
$m->query($sql);
Running a single SQL statement works fine in codeIgniter, but not when I add the second SELECT... statement.
Any ideas (or alternative solutions)?
Thanks
This is not a limitation of CI but that of the database client libraries.
only a single query can be executed at a time.
Why not run two $m->query() statements? That way you can check the success of each individually from CI.
In most SQL interfaces, having multiple statements in a query is problematic because of the different types of result from each. Even when calling a stored procedure, it is necessary to carefully craft the stored procedure not to return extraneous results, though even that can usually be handled with a special, relaxed api which allows multiple results.
insert_id() is your friend!
$this->db->insert_id()
From here http://codeigniter.com/user_guide/database/helpers.html
So something like:
$insert_data = array(
'data' => $my_value
);
$this->db->insert('my_table', $insert_data);
$last_id = $this->db->insert_id();
Instead of running 2 queries, to get the id created after the insert query use:
$this->db->insert_id();
As noted in the other answers, use $this->db->insert_id() is better because there is a chance that another user inserts a row between your two queries. Since PHP can only execute one query at a time, this can become a race condition.
Thanks for everyone's help. The solution that worked for me was
$m = my_model();
$m->data = $value;
$m->save();
echo $m->id;
http://www.codeigniter.com/userguide2/database/active_record.html#caching
You can use Caching to control multiple queries without conflicts.

Multiple mysql statements on same connection

I'm building a search query and was wondering if the code below would be valid. Basically I would set the #keywords variable in the first statement and then use it in the 2nd statement. It seems to be working just fine but I'm not sure if it's a good procedure. Any ideas? :)
The point would be that the query would be more complex and #keyword would show up a number of times.
$list_images_kw = $mysqli_link->prepare("SET #keyword=?;");
$list_images_kw->bind_param('s', $search_string);
$list_images_kw->execute();
$list_images_kw->close();
$list_images = $mysqli_link->prepare(
"SELECT * FROM `images` WHERE UCASE(`images`.img_title) REGEXP #keyword" );
$list_images->execute();
$list_images->close();
If you are interested I have found the series of tutorials for MySQL Stored procuders. Is realy good and very simple to learn how to create your own!
http://www.mysqltutorial.org/mysql-stored-procedure-tutorial.aspx

Categories