Writing PDO DELETE query values - php

I was wondering if we can still use values from a freshly DELETE row as a SELECT or do we really need to SELECT it before ?
Example :
Transform this
$foo = $db->prepare("SELECT * FROM table WHERE id= :id");
$foo->execute(array(
"id" => $table_id
));
$foo = $foo->fetch(PDO::FETCH_ASSOC);
$delete_foo = $bdd->prepare("DELETE FROM table WHERE id = :id");
$delete_foo->execute(array(
"id" => $table_id
));
echo $foo['name'] . " has been deleted !";
Into this :
$delete_foo = $bdd->prepare("DELETE FROM table WHERE id = :id");
$delete_foo->execute(array(
"id" => $table_id
));
$delete_foo = $delete_foo->fetch(PDO::FETCH_ASSOC);
echo $delete_foo['name'] . " has been deleted !";
It would be easier. I was just wondering, I use the 1st method but it just went in mind and I don't find answers.

In postgresql, there is a proprietary extension to the delete statement called RETURNING. Sql Server provides something similar, they call it OUTPUT
For example, OUTPUT DELETED.* in the following DELETE statement
returns all columns deleted from the ShoppingCartItem table:
DELETE Sales.ShoppingCartItem
OUTPUT DELETED.*;
Unfortunately, mysql does not have anything like the above. If you delete a row it's gone (unless you roll back the transaction instead of commiting). If you want to Select the data, you need to execute the SELECT before the DELETE

DELETE queries wont return any results (besides rows affected), so a PDO::query wont have any usable data to fetch.

For the example provided, an extra select query just makes no sense. As you have your $value already.
I would rather say that you need to simplify your PDO code at whole. Compare the below code snippet with yours
$foo = $db->run("SELECT foo FROM table WHERE value = ?", [$value])->fetchColumn();
$db->run("DELETE FROM table WHERE value = ?", [$value]);
echo "$foo has been deleted!";
the run() function can be achieved by a very small PDO modification:
class MyPDO extends PDO
{
public function run($sql, $args = NULL)
{
$stmt = $this->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
the code is taken from my article, Simple yet efficient PDO wrapper

Related

How to print exact sql query before execute in Zend Framework 2

I am working on an application using Zend framework 2. I'm using TableGateway to select, insert, update and delete query.
1. My question is how to print exact sql query before executing INSERT, UPDATE and DELETE statement? For SELECT statement here is my code which is working for me.
$selectedTable = new TableGateway($this->tblName, $this->dbAdapter);
$sql = $selectedTable->getSql();
$select = $sql->select();
if ($trace) {
echo "<br>" . $sql->getSqlstringForSqlObject($select) . "<br>";
exit;
}
else {
$resultSet = $selectedTable->selectWith($select);
unset($selectedTable);
return $resultSet;
}
2. For last inserted id I'm using this code and working fine.
$selectedTable = new TableGateway($this->tblName, $this->dbAdapter);
$selectedTable->insert($dataArray);
$insertId = $selectedTable->adapter->getDriver()->getConnection()->getLastGeneratedValue();
unset($selectedTable);
return $insertId;
But for UPDATE how to get last updated id? and for DELETE how to get affected row? Because for UPDATE and DELETE this code is not working.
Can anyone suggest how to do these job?
1. There should be no difference nor difficulties, do it exaclty the same way on your $insert object. Here how I perform Sql insert and get the SQL string:
$sql = new Sql($this->dbAdapter);
$insert = $sql->insert('table');
[...]
$sqlString = $insert->getSqlString($this->dbAdapter->getPlatform());
2. When you insert a value, you do not know what will be the generated value id before insertion, but you will only know it ater insertion. That's why there is the getLastGeneratedValue-) method for inserted values.
But when you update or delete a value, its id is already defined and you can read it. So all you have to do is to read it from your database. Perform a select before updating or deleting your(s) objetct(s) and you will know all the ids you want.

best way to do not redundant query?

I created the Rest API that are based on the MVC model. So far everything is working well but I want to find a clever way for the future when I'm 20 or 30 models that will communicate with the database. In particular, in every model functions should I write a query like this:
if($stmt = $connection->prepare("SELECT first_name FROM table WHERE id = ?"))
{
$id = 86;
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->bind_result($res);
$stmt->fetch();
echo "My name is => " . $res;
$stmt->close();
}
which becomes annoying. How can I do something like CodeIgniter? I do not want to use external libraries or frameworks because I'm trying to learn how to build a base alone. Now I understand that this question probably does not fit fully into the community standards but I hope someone will understand that it is still a technical question.
To do so you can create a class that contains a class that can accept parameter to communicate with db as the way you want to do.
For example:
you can create a method like function getAll($table) which will return all rows of a the $table. Then you won't need to write same table fetching code again and again. You can just call getAll("users"); which will return all rows of your users table, or getAll('products);` which will return all rows of your 'product' table. I assume that the code inside those helper method won't be difficult for you.
Here is how you can make your given code less redundant.
function findFromTable($table, $id){
if($stmt = $connection->prepare("SELECT first_name FROM $table WHERE id = ?"))
{
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->bind_result($res);
$stmt->fetch();
echo "My name is => " . $res;
$stmt->close();
}
}
Hope that will get you out or redundancy.

PDO : What´s the best method to get the result after insert data to database

I´m very new to PDO. I just wonder what´s the best way to get the result when the data insert to the database comletely. I´m looking around in googl. seems like it´s flexible. That makes me wonder what is correct and what is incorrrect way.
Let see example:
$sql = $conn->prepare("INSERT INTO tb_user(user_name, user_email) VALUES(:user_name,:user_email);
$sql->execute(array(':user_name'=>$user_name, ':user_email'=>$user_email));
$affected_rows = $sql->rowCount();
From this script I want to get result if the data is finish to be insert in database.
If it done-->I will echo it like "complete" and send it back to ajax or etc...
I have tried :
if($affected_rows){
echo"YEZZ!! complete";
}
And
$all = $slq->fetchAll();
if(count($all)) {
echo"YEZZ!! complete";
}
And
if ($sql->execute){
echo"YEZZ!! complete";
//this one i know it will double insert data to database because I called it twice//
But I still want to know when can I use this method
And maybe more ways out there which make me crazy and want to know what is the best way to get result if the thing is done:
AFter insert, after delete, after update these 3 statements is the most important to know each.
Any suggestions could be wonderful !
}
}
you could do:
$id = $conn->lastInsertId('IDCOLUMN');
and then execute a query and search for the id
$stmt = $conn->prepare("SELECT * FROM tb_user WHERE IDCOLUMN = :id");
$stmt->execute(array("id", $id);
if($stmt->rowCount() > 0) {
$result = $stmt->fetch(PDO::FETCH_ASSOC);
}
the result variable will contain your last inserted record
Yes, your approach with rowCount() is a right one. Stick with it.

Select ignores where clause using Zend_Db_Select

$table = new Zend_Db_Table(array('name'=>'rules'));
$select = $table->select();
$select->setTable($table);
$select->setIntegrityCheck(false);
$select = $select
->from(array('ru'=>'rules'),array('ru.*'))
->join(array('ro'=>'roles'),'ro.id=ru.role_id',array('role_id'=>'ro.id'))
->join(array('g'=>'groups'),'ro.group_id=g.id',array('group_id'=>'g.id'))
->join(array('ug'=>'user_groups'),"ug.group_id=g.id",array('user_group_id'=>'ug.id'))
->where("ug.user_id={$userId}")
->where("ru.resource='{$resource}'")
->where("ru.privilege='{$privilege}'");
echo "select: ".$select->__toString();
$row = $table->fetchAll();
I have the preceding code,but when I try fetchAll() it returns all rows in the table, ignoring the where clause, when I use fetchRow() it returns the first row it finds, ignoring the where clause, I printed the SQL statement and run it separately and it executes correctly
any clue ?
This is how you would create a db select object correctly
$db = Zend_Db::factory( ...options... );
$select = new Zend_Db_Select($db);
Or you use the database adapter's select() method
$db = Zend_Db::factory( ...options... );
$select = $db->select();
And you can add clauses
// Build this query:
// SELECT *
// FROM "table1"
// JOIN "table2"
// ON "table1".column1 = "table2".column1
// WHERE column2 = 'foo'
$select = $db->select()
->from('table1')
->joinUsing('table2', 'column1')
->where('column2 = ?', 'foo');
Have a look at the Zend_Db Reference Guide for more information
#ArtWorkAD is right in a certain way. But in your case you're not just using a Zend_Db_Select. You tried to extend a Zend_Db_Select obtained from a Zend_Db_Table (well, you should try to handle a Singleton pattern with Zend_Db_Table but this is another problem). Your current problem (if we except the fact you are certainly reading documentation too fast) is that this line was correct:
$select->setIntegrityCheck(false);
It make your 'select-from-a-zend-db-table' not anymore restricted to the Active Record Mode, and available for extra joins.
But just after that you make a:
$select = new Zend_Db_Select($table);
This is the complete creation of a new object, that you put into your variable. Nothing is kept from previous variable value. You could add a $select=null; just before it would be the same. So this is just canceling the 3 previous lines.
In quite the same confusion mode this line:
$select->setTable($table);
Is not necessary as you're already taking the select from a Zend_Db_Table so the table is already there.
EDIT
And your last and bigger error is:
$table->fetchAll()
You do not use your built $select but your $table, so effectively everything done in your $select is ignored :-) . Fecthing from the $select shoudl give you better results
This should work. Just tested it.
$table = new Zend_Db_Table('rules');
$select = $table->getAdapter()->select();
$select->from(array('ru' => 'rules'), array('ru.*'))
->join(array('ro'=>'roles'), 'ro.id = ru.role_id', array('role_id'=>'ro.id'))
->join(array('g'=>'groups'), 'ro.group_id = g.id', array('group_id'=>'g.id'))
->join(array('ug'=>'user_groups'),"ug.group_id=g.id",array('user_group_id'=>'ug.id'))
->where('ug.user_id = ?', $userId)
->where('ru.resource = ?', $resource)
->where("ru.privilege = ?", $privilege);
echo (string)$select;

how to identify the source table of fields from a mysql query

I have two dynamic tables (tabx and taby) which are created and maintained through a php interface where columns can be added, deleted, renamed etc.
I want to read all columns simulataneously from the two tables like so;-
select * from tabx,taby where ... ;
I want to be able to tell from the result of the query whether each column came from either tabx or taby - is there a way to force mysql to return fully qualified column names e.g. tabx.col1, tabx.col2, taby.coln etc?
In PHP, you can get the field information from the result, like so (stolen from a project I wrote long ago):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
Then you can use it like this:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
So to answer your question directly, the table name data is always sent by MySQL -- It's up to the client to tell you where each column came from. If you really want MySQL to return each column name unambiguously, you will need to modify your queries to do the aliasing explicitly, like #Shabbyrobe suggested.
select * from tabx tx, taby ty where ... ;
Does:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
work?
I'm left wondering what you are trying to accomplish. First of all, adding and removing columns from a table is a strange practice; it implies that the schema of your data is changing at run-time.
Furthermore, to query from the two tables at the same time, there should be some kind of relationship between them. Rows in one table should be correlated in some way with rows of the other table. If this is not the case, you're better off doing two separate SELECT queries.
The answer to your question has already been given: SELECT tablename.* to retrieve all the columns from the given table. This may or may not work correctly if there are columns with the same name in both tables; you should look that up in the documentation.
Could you give us more information on the problem you're trying to solve? I think there's a good chance you're going about this the wrong way.
Leaving aside any questions about why you might want to do this, and why you would want to do a cross join here at all, here's the best way I can come up with off the top of my head.
You could try doing an EXPLAIN on each table and build the select statement programatically from the result. Here's a poor example of a script which will give you a dynamically generated field list with aliases. This will increase the number of queries you perform though as each table in the dynamically generated query will cause an EXPLAIN query to be fired (although this could be mitigated with caching fairly easily).
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
The result is a query that looks like this, with the table and column name separated by two underscores (or whatever delimeter you like, see the third parameter to aliasFields()):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
From there, when you iterate over the results, you can just do an explode on each field name with the same delimeter to get the table name and field name.
John Douthat's answer is much better than the above. It would only be useful if the field metadata was not returned by the database, as PDO threatens may be the case with some drivers.
Here is a simple snippet for how to do what John suggetsted using PDO instead of mysql_*():
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}

Categories