Joomla: Using JDatabaseQuery to represent an insert .. select query? - php

So I need to run a long(ish) query to insert a new row into a table, based on values of another row elsewhere in the database. This is running in Joomla 3.1.5
Typically, you can use MySql's INSERT .. SELECT syntax to easily do this, but I'm looking for a way to keep close to Joomla's query builder, example:
<?php
// ...
// Base Tables & Columns.
$my_table = '#__my_table';
$columns = array('column_one', 'column_two');
// Set up the database and query.
$db = JFactory::getDBO();
$query = $db->getQuery(true);
// Escape / quote the table name.
$my_table = $db->quoteName($my_table);
// Escape all columns.
$cols = array_map(array($db, 'quoteName'), $cols);
$query
->insert($my_table)
->columns($columns)
// E.g. ->select( ... )->from( ... ) ...
$db->setQuery($query);
$result = $db->query();
// ...
?>
Of course, the example comment won't work, but I was wondering if there was a way which would allow me to perform something similar (without needing to run a separate query elsewhere).
Naturally, if there's no way to perform this type of query, I can just drop to using a raw query string.

The docblocks of many JDatabaseQuery methods include the following statement
* Note that you must not mix insert, update, delete and select method calls when building a query.
This is because ... to over simplify but as an example how would we know which list of columns (or which where clause etc) to put where when we are building the query.
But there are ways that you can get around this limitation by building your query in a slightly more complex way (which is fair since it's a more complex query). So for example
$db = JFactory::getDBO();
$queryselect = $db->getQuery(true);
$queryselect->select($db->quoteName(array('id','title','alias')))
->from($db->quoteName('#__content'));
$selectString = $queryselect->__toString();
$queryInsert = $db->getQuery(true);
$queryInsert->columns($db->quoteName(array('id','title','alias')))
->insert($db->quotename('#__newtable'));
$db->setQuery($queryInsert . $selectString);
$db->execute();

Related

PHP/MYSQL:Carry out UPDATE within SELECT query

There are many questions on SO about this but I cannot find one that quite meets my situation.
I want to use the values in some fields/columns of a table to set the value of a third field/column
In other words something like:
table races
athleteid|difficulty|score|adjustedscore
$sqlSelect = "SELECT athleteid,difficulty,score FROM races";
$res = mysql_query($sqlSelect) or die(mysql_error());
while ($row = mysql_fetch_array($res)){
$adjustedscore=difficulty*score;
$sqlupdate = "UPDATE race, set adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
$resupdate = mysql_query($sqlupdate);
}
My understanding, however, is that MYSQL does not support update queries nested in select ones.
Note, I have simplified this slightly. I am actually calculating the score based on a lot of other variables as well--and may join some tables to get other inputs--but this is the basic principal.
Thanks for any suggestions
You can run:
UPDATE `races`
SET `adjustedscore` = `difficulty` * `score`
WHERE `athleteid` IN (1, 2, 3, ...)
First of all, as previous commentators said, you should use PDO instead of mysql_* queries.
Read about PDO here.
When you'll get data from DB with your SELECT query, you'll get array. I recommend you to use fetchAll() from PDO documentation.
So, your goal is to save this data in some variable. Like you did with $row.
After that you'll need to loop over each array and get your data:
foreach($row as $r) {
//We do this to access each of ours athlete data
$adjustedscore= $row[$r]["difficulty"]* $row[$r]["score"];
//Next row is not clear for me...
$query = "UPDATE race SET adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
And to update we use PDO update prepared statement
$stmt = $dbh->prepare($query);
$stmt->execute();
}

LIKE SQL with parameters throwing Invalid Parameter Number

So I'm trying to use a "LIKE" in the SQL, basically to see if a player is in a team already. Here's the code I have:
$checkifonlytwo = "SELECT * FROM sg_turn_teams WHERE joinid = :joinid AND players LIKE '%:ownerid,%'";
$paramstwo = array(
":joinid" => $joinid,
":ownerid" => $_SESSION['user']['id']
);
try{
$stmttwo = $db->prepare($checkifonlytwo);
$resulttwo = $stmttwo->execute($paramstwo);
}
catch(PDOException $ex){
die("Failed to run query #2: " . $ex->getMessage());
}
Also as you can see I want it to be LIKE '%1,%' for example, so the comma at the end too.
My table structure looks like this.
EDIT, the players is going to be like "1,2,3" without the names because the users are able to change their name. The picture is with names, but it's supposed to be 1,2,3
Foreword. I decided to make this a community wiki. I did not want to gain anything from this, except for the OP and others visiting the question.
As I said in comments, you're going about it the wrong way with the comma in there ownerid,.
What you need to do is implode on the array and using IN().
Borrowed from https://stackoverflow.com/a/12151295/
$e = 0;
while($e<$num1){
$units = 0;
$r = 0;
$SO_Line_Item=mysql_result($result1,$e,"SO_Line_Item");
foreach ($Boxes[$e] as $a => $b)
{
$zzz[] = $Boxes[$e][$r];
$ce = count($Boxes[$e]);
$r++;
}
//end inner foreach
$products = implode(',', array_fill(0,$ce, '?'));
$db = new PDO('mysql:host=192.168.1.197 ;dbname=Tracking', $dbuser,$dbpass);
$stmt = $db->prepare("SELECT Box_Num,Timestamp,E3_SN,Assy_Status FROM Current_Box WHERE Box_Num IN( $products )");
$stmt->execute($zzz);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
unset($zzz);
$e++;
}
and from https://stackoverflow.com/a/2814703/
$ids = array(2, 4, 6, 8);
// prepare a string that contains ":id_0,..,:id_n" and include it in the SQL
$plist = ':id_'.implode(',:id_', array_keys($ids));
$sql = "SELECT * FROM someTable WHERE someId IN ($plist)";
// prepare & execute the actual statement
$parms = array_combine(explode(",", $plist), $ids);
$stmt = $PDO->prepare($sql);
$rows = $stmt->execute($parms);
From comments:
"You might want to use association tables rather than storing the information the way you are storing it. – Maximus2012"
As mentioned in the comments, some questions/answers from SO that demonstrate the concept of Association tables along with composite primary keys:
Mysql : Association table
How to use an MySQL association table to return categories not currently assigned to an entry
If OP decides to go with this structure then the queries would need to be changed to make use of LEFT JOIN and/or use a sub-query with IN clause. There are plenty of examples of both on SO. One that I could find with a simple search (please ignore the slow query part and look at the examples to demonstrate the concept):
MySQL - SELECT WHERE field IN (subquery) - Extremely slow why?

How to Search Values in all table in a mysql database?

How i find the Last Updated Values inside the all the table field in a given Database?
Search results for "%2015-07-08%" at least one of the words:
Its not impossible, but its not trivial either. I don't think that there is an easy way to do this with SQL alone (I assume that you use mySQL, but you haven't really specified what kind of database you are using).
One way to do it is make a script that uses INFORMATION_SCHEMA tables to find the relevant tables and columns to search through, then iterate those in PHP and execute queries that search those columns and tables.
Edit:
Just for the sake of doing it I made a small example of what i mean, this code uses PDO:
function findAll($search_str, $database, $types = ['tinytext','blob','varchar','text','longblob']){
global $pdo;
foreach($types as &$t){
$t = "'" . $t . "'";
}
$types = implode(',',$types);
$s = $pdo->prepare("
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.columns
WHERE
TABLE_SCHEMA = :database
AND DATA_TYPE IN ($types)
");
$s->bindValue(':database', $database);
$s->execute();
$results = [];
foreach($s->fetchAll(\PDO::FETCH_ASSOC) as $column){
$search = $pdo->prepare("SELECT * FROM $database.${column['TABLE_NAME']} WHERE ${column['COLUMN_NAME']} LIKE :search_str");
$search->bindValue(':search_str', $search_str);
$search->execute();
$result = $search->fetchAll(\PDO::FETCH_ASSOC);
if(count($result))
$results[$column['TABLE_NAME']] = isset($results[$column['TABLE_NAME']])
? array_merge(
$results[$column['TABLE_NAME']],
$result
)
: $result;
}
return $results;
}
Example of usage:
findAll('%foobar%','my_database');
findAll('%2015-07-08%','my_database',['date','datetime','timestamp']); //Only search date types...
How about checking the latest value of the key column e.g. in an column with auto increment you check the highest value? This is just a suggestion though while assuming you have such a column. The other idea would be to add a column with a timestamp data type so that you can update it automatically during inserts or updates.

CakePHP 3 Raw SQL Query

I'm using CakePHP 3, I need to run a raw SQL query on multiple tables. In CakePHP 2, this could be done by using the query() method on any model ( $this->Messages->query("select..") ).
I need the method that allows me to run a SQL query in CakePHP 3. Following is the code snippet I'm using:
$aumTable = TableRegistry::get('Messages');
$sql = "SELECT (SELECT COUNT(*) FROM `messages`) AS `Total_Count`,
(SELECT COUNT(*) FROM `messages_output`) AS `Total_Output_Count`,
(SELECT COUNT(*) FROM `messages_output` WHERE `is_success`=1) AS `Total_Successful_Output_Count`,
(SELECT COUNT(*) FROM `messages_output` WHERE `is_success`=0) AS `Total_Error_Output_Count`,
(SELECT COUNT(*) FROM `users`) AS `Total_User_Count`;";
// to run this raw SQL query what method should i use? query() doesn't work..
// $result = $aumTable->query($sql); ??
// $result = $aumTable->sql($sql); ??
If you can provide links to CakePHP 3 model documentation where I can find this info, that would be helpful too. I tried searching on google but could only find questions related to CakePHP 2.
First you need to add the ConnectionManager:
use Cake\Datasource\ConnectionManager;
Then you need to get your connection like so:
// my_connection is defined in your database config
$conn = ConnectionManager::get('my_connection');
More info: http://book.cakephp.org/3.0/en/orm/database-basics.html#creating-connections-at-runtime
After that you can run a custom query like this:
$stmt = $conn->execute('UPDATE posts SET published = ? WHERE id = ?', [1, 2]);
More info: http://book.cakephp.org/3.0/en/orm/database-basics.html#executing-queries
And then you are ready to fetch the row(s) like this:
// Read one row.
$row = $stmt->fetch('assoc');
// Read all rows.
$rows = $stmt->fetchAll('assoc');
// Read rows through iteration.
foreach ($rows as $row) {
// Do work
}
More info: http://book.cakephp.org/3.0/en/orm/database-basics.html#executing-fetching-rows
The documentation for this is here: http://book.cakephp.org/3.0/en/orm/database-basics.html#executing-queries
But what's not written there is how to execute it. Because it cost me a while, here is the solution for that:
1.You need to add
use Cake\Datasource\ConnectionManager;
2.init the ConnectionManager (as mentioned above)
$conn = ConnectionManager::get('my_connection');
3.Execute your SQL with something like this
$firstName = $conn->execute('SELECT firstname FROM users WHERE id = 1');
The question is already very old, but I still find it frequently.
Here is a solution for CAKEPHP 3.6 and (short) for newer PHP Versions.
It is not necessary to use the ConnectionManager get function and often it does not make sense, as the connection name may not be known at all. Every table has its / a connection which one can get with getConnection ().
If you are already in the Messages Table (src/Model/Table/MessagesTable.php), you can simply use the Connection
$con = $this->Messages->getConnection();
If you are not there (what your code would suggest with TableRegistry::get(), you can do that with this table as well
// $aumTable is declared in question
$con = $aumTable->getConnection();
then you can execute a RAW query as shown above:
$result = $con->execute ();
// short
$result = $this->Messages->getConnection()->execute ('Select * from ...')
// or ($aumTable is declared in question)
$result = $aumTable->getConnection()->execute ('Select * from ...');

PHP MySQLi insert ids from multi_query()

Is there a way to get the last generated auto_increment IDs after inserting several rows with mysqli multi_query function?
EDIT:
I managed to get it work by adding SELECT LAST_INSERT_ID(); after each INSERT query in the multi query and then use the mysqli_use_result to get all ids, and I think this is the best way.
You can fetch the different insert ids by calling MySQLi's next_result() for each consecutive insert statement. As far as I know, you don't have to store any results as long as the queries are insert statements or something else that doesn't return a result set.
$sql = new MySQLi("...");
$query = "INSERT STATEMENT NUMBER ONE;";
$query .= "INSERT STATEMENT NUMBER TWO;";
$query .= "INSERT STATEMENT NUMBER THREE";
$sql->multi_query($query);
// The first insert id will be available at once
$id1 = $sql->insert_id;
// The second needs to be handeled a little differently
$sql->next_result();
$id2 = $sql->insert_id;
// And lastly the third one
$sql->next_result();
$id3 = $sql->insert_id;
You can also put this in a loop if you are unsure of how many insert statements there are:
$ids = array();
do
{
$ids[] = $sql->insert_id;
$sql->next_result();
} while($sql->more_results());
This is untested pseudo code (as you might have figured), but it should work.

Categories