I am trying to create a temporary table from the results of multiple tables that are alike (same table structure). After creating the temporary table and runing the subsequent queries, I would like to store the results from the temporary table in an array to be accessible later in the script/program. I have tried searching for an answer and can't seem to find one.
I have tried nextRowset() as well as separating the queries, but nothing seems to be working like I expect it to work.
Here is my code:
$pdo = new PDO("mysql:host=".$_SESSION['server'].";dbname=data".$_SESSION['sysident'],$user,$pass);
$stmt = $pdo->prepare("DROP TABLE IF EXISTS $tabletocreate;
CREATE TEMPORARY TABLE $tabletocreate LIKE table1;
INSERT INTO $tabletocreate (SELECT * FROM table1 WHERE (MISC LIKE '%:memno%' OR MEMNO = :memno)) UNION (SELECT * FROM table2 WHERE (MISC LIKE '%:memno%' OR MEMNO = :memno)) UNION (SELECT * FROM table3 WHERE (MISC LIKE '%:memno%' OR MEMNO = :memno)) ORDER BY SLIPNO;
SELECT * FROM $tabletocreate");
$stmt->bindParam(":memno",$_SESSION['memno']);
$stmt->execute();
$stmt->nextRowset();
$test = $stmt->fetchAll();
print_r($test);
I am unsure as to why the results are not being stored into the array. From what I can tell, everything seems right and no errors occur when the script is ran. I appreciate any help that anyone can offer.
UPDATE - I found out why the query wasn't working. I was using a "-" in the table name I was trying to create which isn't allowed.
You cannot run multiple queries in a single ->query() call. This is a security measure in the underlying PHP mysql drivers, to prevent some form of SQL injection attacks. Doesn't matter which DB interface library you're using, because they all use the same underlying drivers. You'll have to run each seperate query separately:
->query("DROP TABLE IF EXISTS ...");
->query("CREATE TEMPORARY TABLE ...");
->query("INSERT INTO ...");
etc...
I was trying to create a table name with a "-" in the table name. After removing this from the table name, all the queries executed successfully and my PHP code worked as intended.
Related
I know I am supposed to create a temporary table based on an existing row, remove the id and then insert an new row in my "real" table based on the temporary table. But it does not work in my prestashop.
$id = 4;
$createTemp = Db::getInstance()->Execute('CREATE TABLE temp_table AS SELECT * FROM my_table WHERE id="'.$id.'"');
$updateTemp = Db::getInstance()->Execute('UPDATE temp_table SET id=NULL');
$insertQuery = Db::getInstance()->Execute('INSERT INTO my_table SELECT * FROM temp_table');
$deleteTemp = Db::getInstance()->Execute('DROP TABLE temp_table');
If I make a var_dump of those I always get a FALSE. I tried to make the select only in a query and it does work so my SELECT * FROM my_table WHERE id="'.$id.'" is correct.
I need to be able to duplicate a row and I could'nt find another/a better way to do so. What do I have to change in my code to make it work ?
If source data is OK your code should work,
I would enable Prestashop mode_dev so you can see the query errors on-screen for better debug.
Since you're working with Prestashop - maybe your "my_table" id is not called id but something different like "id_product" ?
If this is the case, first create will fail and all other queries will fail consequently.
I have a lot of tables in my SQL database, and I want to delete from all tables from it where the IP matches a certain IP in one statement/Query. Is there a way to do it quickly?
Something like:
DELETE FROM * tables where ip = '$ip';
Is there a way to do this?
Like this
$tables = ['table1','table2','table3'];
foreach($tables as $table){
//DELETE FROM `$table` tables where ip = :ip;
}
Just make absolutely certain you are using prepared statements, and "canned" table names. Never concatenate user input into your sql.
Imagine this $ip = "1' OR 1=1"; Now all your data has been deleted. AKA sql Injection.
Because your innocent query:
DELETE FROM table where ip = '$ip'
Becomes:
DELETE FROM table where ip = '1' OR 1=1
AND 1 is always equal to 1
If you can't see the data your putting in when you look at the query, use prepared statements. Because, you never know when you will re-purpose a piece of code and if it's not done right from the get go, your setting yourself up for a lot of headaches.
This may be a one time thing you are doing, but if you plan to leave the code around, I would still use prepared statements.
Can't you just separate them by a semicolon?
DELETE FROM table1 WHERE id = 1;
DELETE FROM table2 WHERE id = 1;
DELETE FROM table3 WHERE id = 1;
Looking into the details of the question that you have provided. You can do this with the help of Dynamic SQL.
Step 1) With the help of information_schema, prepare the dynamic SQL to delete the record from the table. You will get dynamic SQL like below
Delete from table1 where ColumnName = 'IPAddress';
Delete from table2 where ColumnName = 'IPAddress';
Step 2) With the help of Execute Statement. Run that dynamic SQL and this will delete all the records from those tables where the record has IP address in that column.
I am using MySql and have a situation which is a lot like a correlated subquery except that the data in the inner query is not in the database - but in a PHP session.
If all the data were in the database, the query would look something like this:
SELECT * FROM tableA WHERE (tableA.valueA && (
SELECT valueB FROM tableB WHERE tableB.id = tableA.id));
My problem is that I have no tableB. Instead I have a PHP array. How can I inject the array into the query? Should I attempt to create a temporary table somewhere? Or perhaps I should be trying to declare the array as a variable?
The information in the PHP array is specific to each user and changes rapidly. Also, there will be lots of queries so performance is a consideration.
See comments from Wrikken above - I have made this a temporary table and it seems to be a fine solution.
I'm getting a weird result from a quite long query, which I will simplify here:
DROP TEMPORARY TABLE IF EXISTS table1;
CREATE TEMPORARY TABLE table1 AS
(SELECT
parent.id as parent_id,
times.a_time,
times.sequence,
FROM times
LEFT JOIN parent ON times.parent_id=parent.id
WHERE times.stop_id=10);
DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2 AS
(SELECT
parent.id as parent_id,
times.b_time,
times.sequence,
FROM times
LEFT JOIN parent ON times.parent_id=parent.id
WHERE times.stop_id=15 );
--here comes PDO->exec();
SELECT table1.*, table2.b_time
FROM table1
LEFT JOIN table2 ON table1.parent_id=table2.parent_id
WHERE table2.parent_id IS NOT NULL AND table1.sequence<table2.sequence
ORDER BY table1.a_time
I'm testing the query using EMS MySQL Manager 2007, and in PHP I'm using PDO query.
In order to get the final result, (I know that PDO doesn't support running this full query at once and giving back the result set), I run PDO->exec() after temporary tables creation (see comment in the query), and then I run PDO->query() on the last SELECT:
$db = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$tempTablesSQL='DROP TEMPORARY TABLE IF EXISTS...'; //create temporary tables
$db->exec($tempTablesSQL);
$sql='SELECT table1.*, table2.b_time ...'; //JOIN and SELECT the results
$results=array();
foreach($db->query($sql) as $row){
$results[]=$row;
}
print_r($results);
In MySQL Manager I run the whole query at once, and for those specific IDs I'm getting 29 rows as result (which is correct, because the records are inserted from a previously parsed file, and by comparing the results to the file I know they are good).
But in PHP, I'm getting only 25 results, and totally wrong values for b_time.
So, my questions are:
why do I get wrong results?
is my approach of calling this query wrong (in PHP)?
Any help is appreciated.
--EDIT--
It's not just PDO, I tried with mysqli_multi_query, I'm getting the same wrong results.
One important thing I noticed is: if I use regular tables instead of the temporary, the results are fine.
Let my try to put a couple of suggestions on the second part of your question which is is my approach of calling this query wrong?
First of all it looks like you don't need to create any temp tables. Based on what you showed the whole thing can be a single query like
SELECT q1.parent_id, q1.a_time, q1.sequence, q2.b_time
FROM
(
SELECT p.id parent_id, t.a_time, t.sequence
FROM times t LEFT JOIN parent p
ON t.parent_id=p.id
WHERE t.stop_id = ?
) q1 LEFT JOIN
(
SELECT p.id as parent_id, t.b_time, t.sequence
FROM times t LEFT JOIN parent p
ON t.parent_id=parent.id
WHERE t.stop_id = ?
) q2 ON q2.parent_id IS NOT NULL
AND q1.sequence < q2.sequence
ORDER BY q1.a_time
And execute it as a prepared statement
...
$sql = 'SELECT ...'; // the whole thing from above
$query = $db->prepare($sql);
$query->execute(array($stop_id1, $stop_id2));
$result = $query->fetchAll(PDO::FETCH_ASSOC);
var_dump($result);
Now even if for some reason you have to use temp tables and perform some manipulations along the way before returning the result set then I'd suggest to wrap it up a stored procedure
DELIMITER $$
CREATE PROCEDURE sp_myproc (IN stop_id1 INT, IN stop_id2 INT, ...)
BEGIN
DROP TEMPORARY TABLE IF EXISTS table1;
CREATE TEMPORARY TABLE table1 AS
...
WHERE times.stop_id = stop_id1;
DROP TEMPORARY TABLE IF EXISTS table1;
CREATE TEMPORARY TABLE table1 AS
...
WHERE times.stop_id = stop_id2
-- return the resultset
SELECT table1.*, table2.b_time
FROM table1
...
END$$
DELIMITER ;
And call your procedure once from php
...
$sql = 'CALL sp_myproc(?, ?)';
$query = $db->prepare($sql);
$query->execute(array($stop_id1, $stop_id2));
$result = $query->fetchAll(PDO::FETCH_ASSOC);
var_dump($result);
Now regarding the first part of your question why do I get wrong results? OUTER joins can be tricky and especially when you chain them. You can easily filter some rows out or produce additional rows (which happens most often).
Those few joins that you removed may be the cause.
Anyway provided information is not enough for conclusive answer.
But I would suggest instead of returning columns as table1.* specify all columns explicitly and give explicit aliases for columns that have the same names in different tables that are part of a join.
I am joining two tables: customers and queries.
I am getting the full_name from the customers table and the description from the queries table.
I am wondering if it is possible to have the results of an SQL join split into arrays that correspond with the table the data came from? For example:
$STH = $DBH->prepare("SELECT queries.description, customers.full_name FROM queries INNER JOIN customers ON queries.customer_id = customers.id");
$STH->execute();
$queries = $STH->fetchAll();
At the moment, I can access my data like this: $queries[0]['description'] and $queries[0]['full_name']
However, my question is whether there is an easy way to get the data like so: $job[0]['query']['description'] and $job[0]['customer']['full_name'].
Just as teresko mentioned, I can't understand why you'd need that.
I can only imagine you want to see on the PHP code what are the table that contained the information.
Maybe you could do something like SELECT queries.description as queries_description, then your php code would look like $queries['queries_description']. Would it be enough?
You can loop through the results in PHP and convert it to the data structure you want, but you cannot (as far as I know) automatically group the data into arrays based on the source table. A (somewhat messy) alternative, using SQL is to use a multi-query and create a temp table from your original results, then select the results on a per-table basis, like so:
CREATE TEMPORARY TABLE q AS
(SELECT queries.description, customers.full_name FROM queries
INNER JOIN customers
ON queries.customer_id = customers.id
);
SELECT q.description FROM q;
SELECT q.full_name FROM q;
So, in those SELECT statements, you'll have to list all the columns that you want for each result. Then in PHP, you'll have to iterate over each resultset and put the data into arrays (or objects/whatever) as needed. Errr. A fetchAll will still not get you what you want, but a fetchAll on the first non-empty resultset will get you all the rows from queries and the 2nd will get you all the rows from customers