理论-如何打印出真正的sql,不只是准备好的声明吗?
-
21-09-2019 - |
题
我们正在使用的学说,一个PHP奥姆.我创造一个查询这样的:
$q = Doctrine_Query::create()->select('id')->from('MyTable');
然后在功能上我加入各种其条款,并事情作适当的,就像这样
$q->where('normalisedname = ? OR name = ?', array($string, $originalString));
后来,前 execute()
-ing,即查询对象,我想打印出来的原SQL为了研究它,做到这一点:
$q->getSQLQuery();
然而,只有打印出的准备的声明,不充分的查询。我想看看它是什么送到MySQL,但是它是印刷出一份声明,其中包括 ?
's。是否有某种方式看到的'全面'询问?
解决方案
理论是不是发送一个"真正的SQL query"数据库服务器:它实际上使用准备好的发言,这意味着:
- 发送的发言,它准备(这是什么是返回的
$query->getSql()
) - 而且,那么,发送的参数(返回的
$query->getParameters()
) - 并执行该准备好的发言
这意味着永远不会有"真实的"SQL query on PHP侧因此,原则不能显示它。
其他提示
一个工作示例:
$qb = $this->createQueryBuilder('a');
$query=$qb->getQuery();
// SHOW SQL:
echo $query->getSQL();
// Show Parameters:
echo $query->getParameters();
您可以检查您的应用程序执行的查询,如果您登录所有查询在mysql中:
http://dev.mysql.com/doc/ refman / 5.1 / EN /查询log.html
会有更多的查询不仅是一个你正在寻找,但你可以grep吧。
但通常->getSql();
作品
编辑:
,以查看所有我使用
MySQL的查询sudo vim /etc/mysql/my.cnf
和添加这些2行:
general_log = on
general_log_file = /tmp/mysql.log
和重启MySQL
我已经创建了一个记录器Doctrine2那个不正是此。它“水合物”的参数化SQL查询使用学说2自己的数据类型conversors的值。
<?php
namespace Drsm\Doctrine\DBAL\Logging;
use Doctrine\DBAL\Logging\SQLLogger,
Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* A SQL logger that logs to the standard output and
* subtitutes params to get a ready to execute SQL sentence
* @author dsamblas@gmail.com
*/
class EchoWriteSQLWithoutParamsLogger implements SQLLogger
{
const QUERY_TYPE_SELECT="SELECT";
const QUERY_TYPE_UPDATE="UPDATE";
const QUERY_TYPE_INSERT="INSERT";
const QUERY_TYPE_DELETE="DELETE";
const QUERY_TYPE_CREATE="CREATE";
const QUERY_TYPE_ALTER="ALTER";
private $dbPlatform;
private $loggedQueryTypes;
public function __construct(AbstractPlatform $dbPlatform, array $loggedQueryTypes=array()){
$this->dbPlatform=$dbPlatform;
$this->loggedQueryTypes=$loggedQueryTypes;
}
/**
* {@inheritdoc}
*/
public function startQuery($sql, array $params = null, array $types = null)
{
if($this->isLoggable($sql)){
if(!empty($params)){
foreach ($params as $key=>$param) {
$type=Type::getType($types[$key]);
$value=$type->convertToDatabaseValue($param,$this->dbPlatform);
$sql = join(var_export($value, true), explode('?', $sql, 2));
}
}
echo $sql . " ;".PHP_EOL;
}
}
/**
* {@inheritdoc}
*/
public function stopQuery()
{
}
private function isLoggable($sql){
if (empty($this->loggedQueryTypes)) return true;
foreach($this->loggedQueryTypes as $validType){
if (strpos($sql, $validType) === 0) return true;
}
return false;
}
}
用法示例:; 下面的代码和平将回显在标准输出任何INSERT,UPDATE,以$ EM实体管理器生成DELETE SQL语句,
/**@var \Doctrine\ORM\EntityManager $em */
$em->getConnection()
->getConfiguration()
->setSQLLogger(
new EchoWriteSQLWithoutParamsLogger(
$em->getConnection()->getDatabasePlatform(),
array(
EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_UPDATE,
EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_INSERT,
EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_DELETE
)
)
);
有没有其他真正的查询,这是语句是如何准备工作。的值绑定在数据库服务器中,而不是在应用层。
请参阅我的回答这个问题:的在PHP和PDO,如何检查最终SQL参数化查询?
(此处重复方便:)
使用准备的语句与parametrised值并不是简单的另一种方式来动态创建SQL的字符串。您在创建数据库准备好的语句,然后单独发送的参数值。
那么,什么是可能发送到数据库将是一个
PREPARE ...
,然后SET ...
最后EXECUTE ....
您将无法得到一些SQL字符串像
SELECT * FROM ...
,即使它会产生相同的结果,因为没有这样的查询是以往任何时候实际发送到数据库中。
getSqlQuery()
不在技术上显示整个SQL命令,但是它的很多有用的时候你可以看到的参数。
echo $q->getSqlQuery();
foreach ($q->getFlattenedParams() as $index => $param)
echo "$index => $param";
使这种模式的更多的可重复使用,有一个很好的方法描述 评论意见 在 原SQL从理论的查询对象.
我的解决办法:
/**
* Get SQL from query
*
* @author Yosef Kaminskyi
* @param QueryBilderDql $query
* @return int
*/
public function getFullSQL($query)
{
$sql = $query->getSql();
$paramsList = $this->getListParamsByDql($query->getDql());
$paramsArr =$this->getParamsArray($query->getParameters());
$fullSql='';
for($i=0;$i<strlen($sql);$i++){
if($sql[$i]=='?'){
$nameParam=array_shift($paramsList);
if(is_string ($paramsArr[$nameParam])){
$fullSql.= '"'.addslashes($paramsArr[$nameParam]).'"';
}
elseif(is_array($paramsArr[$nameParam])){
$sqlArr='';
foreach ($paramsArr[$nameParam] as $var){
if(!empty($sqlArr))
$sqlArr.=',';
if(is_string($var)){
$sqlArr.='"'.addslashes($var).'"';
}else
$sqlArr.=$var;
}
$fullSql.=$sqlArr;
}elseif(is_object($paramsArr[$nameParam])){
switch(get_class($paramsArr[$nameParam])){
case 'DateTime':
$fullSql.= "'".$paramsArr[$nameParam]->format('Y-m-d H:i:s')."'";
break;
default:
$fullSql.= $paramsArr[$nameParam]->getId();
}
}
else
$fullSql.= $paramsArr[$nameParam];
} else {
$fullSql.=$sql[$i];
}
}
return $fullSql;
}
/**
* Get query params list
*
* @author Yosef Kaminskyi <yosefk@spotoption.com>
* @param Doctrine\ORM\Query\Parameter $paramObj
* @return int
*/
protected function getParamsArray($paramObj)
{
$parameters=array();
foreach ($paramObj as $val){
/* @var $val Doctrine\ORM\Query\Parameter */
$parameters[$val->getName()]=$val->getValue();
}
return $parameters;
}
public function getListParamsByDql($dql)
{
$parsedDql = preg_split("/:/", $dql);
$length = count($parsedDql);
$parmeters = array();
for($i=1;$i<$length;$i++){
if(ctype_alpha($parsedDql[$i][0])){
$param = (preg_split("/[' ' )]/", $parsedDql[$i]));
$parmeters[] = $param[0];
}
}
return $parmeters;}
使用示例:
$query = $this->_entityRepository->createQueryBuilder('item');
$query->leftJoin('item.receptionUser','users');
$query->where('item.customerid = :customer')->setParameter('customer',$customer)
->andWhere('item.paymentmethod = :paymethod')->setParameter('paymethod',"Bonus");
echo $this->getFullSQL($query->getQuery());
可以很容易地使用以下方法访问SQL参数。
$result = $qb->getQuery()->getSQL();
$param_values = '';
$col_names = '';
foreach ($result->getParameters() as $index => $param){
$param_values .= $param->getValue().',';
$col_names .= $param->getName().',';
}
//echo rtrim($param_values,',');
//echo rtrim($col_names,',');
因此,如果打印出$param_values
和$col_names
,就可以得到通过SQL和相应的列名的参数值。
注意:如果$param
返回一个数组,则需要重新迭代,如内部IN (:?)
通常是参数是作为嵌套阵列
与此同时,如果你发现了另一种方法,请热情地向与我们分享:)
谢谢!
更多透明溶液:
/**
* Get string query
*
* @param Doctrine_Query $query
* @return string
*/
public function getDqlWithParams(Doctrine_Query $query){
$vals = $query->getFlattenedParams();
$sql = $query->getDql();
$sql = str_replace('?', '%s', $sql);
return vsprintf($sql, $vals);
}
您可以使用:
$query->getSQL();
如果你正在使用MySQL,你可以使用工作台来查看正在运行的SQL语句。 还可以使用通过使用下面的视图从MySQL的运行的查询:
SHOW FULL PROCESSLIST \G
也许这可以是有用的人:
// Printing the SQL with real values
$vals = $query->getFlattenedParams();
foreach(explode('?', $query->getSqlQuery()) as $i => $part) {
$sql = (isset($sql) ? $sql : null) . $part;
if (isset($vals[$i])) $sql .= $vals[$i];
}
echo $sql;
Solution:1
====================================================================================
function showQuery($query)
{
return sprintf(str_replace('?', '%s', $query->getSql()), $query->getParams());
}
// call function
echo showQuery($doctrineQuery);
Solution:2
====================================================================================
function showQuery($query)
{
// define vars
$output = NULL;
$out_query = $query->getSql();
$out_param = $query->getParams();
// replace params
for($i=0; $i<strlen($out_query); $i++) {
$output .= ( strpos($out_query[$i], '?') !== FALSE ) ? "'" .str_replace('?', array_shift($out_param), $out_query[$i]). "'" : $out_query[$i];
}
// output
return sprintf("%s", $output);
}
// call function
echo showQuery($doctrineQueryObject);
我写了一个简单记录器,其可以与插入的参数日志查询。 安装:
composer require cmyker/doctrine-sql-logger:dev-master
用法:
$connection = $this->getEntityManager()->getConnection();
$logger = new \Cmyker\DoctrineSqlLogger\Logger($connection);
$connection->getConfiguration()->setSQLLogger($logger);
//some query here
echo $logger->lastQuery;
$sql = $query->getSQL();
$parameters = [];
foreach ($query->getParameters() as $parameter) {
$parameters[] = $parameter->getValue();
}
$result = $connection->executeQuery($sql, $parameters)
->fetchAll();
改性@dsamblas功能发挥作用时,参数是日期字符串这样“2019年1月1日”,并且当存在使用在像数组传递
$qb->expr()->in('ps.code', ':activeCodes'),
。所以,做什么都写dsamblas,但这种替换startQuery或看到的差异,并添加我的代码。 (万一他修改的东西在他的功能和我的版本没有修改)。
public function startQuery($sql, array $params = null, array $types = null)
{
if($this->isLoggable($sql)){
if(!empty($params)){
foreach ($params as $key=>$param) {
try {
$type=Type::getType($types[$key]);
$value=$type->convertToDatabaseValue($param,$this->dbPlatform);
} catch (Exception $e) {
if (is_array($param)) {
// connect arrays like ("A", "R", "C") for SQL IN
$value = '"' . implode('","', $param) . '"';
} else {
$value = $param; // case when there are date strings
}
}
$sql = join(var_export($value, true), explode('?', $sql, 2));
}
}
echo $sql . " ;".PHP_EOL;
}
}
没有太大测试
要打印出的SQL查询中学说,使用:
$query->getResult()->getSql();