学说 – 如何打印出真正的SQL,而不仅仅是准备好的声明?

我们正在使用一个PHP ORM Doctrine。 我正在创build一个这样的查询:

$q = Doctrine_Query::create()->select('id')->from('MyTable'); 

然后在函数中添加各种where子句和适当的东西,就像这样

 $q->where('normalisedname = ? OR name = ?', array($string, $originalString)); 

之后,在execute()该查询对象之前,我想打印出原始SQL以检查它,并执行以下操作:

 $q->getSQLQuery(); 

但是,只打印准备的语句,而不是完整的查询。 我想看看它发送给MySQL,而是打印出一个准备好的声明,包括? 的。 有没有办法看到“完整”的查询?

Doctrine没有向数据库服务器发送一个“真正的SQL查询”:它实际上是使用准备好的语句,这意味着:

  • 发送语句,为它准备(这是$query->getSql()返回的内容)
  • 然后,发送参数(由$query->getParameters()
  • 并执行准备好的语句

这意味着在PHP方面从来没有“真正”的SQL查询 – 所以,学说不能显示它。

一个例子..

 $qb = $this->createQueryBuilder('a'); $query=$qb->getQuery(); 

显示SQL: $sql=$query->getSQL();

显示参数: $parameters=$query->getParameters();

你可以检查你的应用程序执行的查询,如果你在mysql中logging所有的查询:

http://dev.mysql.com/doc/refman/5.1/en/query-log.html

会有更多的疑问,不仅是你正在寻找的,但你可以grep它。

但通常->getSql(); 作品

编辑:

查看我使用的所有mysql查询

 sudo vim /etc/mysql/my.cnf 

并添加这两行:

 general_log = on general_log_file = /tmp/mysql.log 

并重新启动mysql

getSqlQuery()在技​​术上显示了整个SQL命令,但是当你看到参数的时候,它也是非常有用的。

 echo $q->getSqlQuery(); foreach ($q->getFlattenedParams() as $index => $param) echo "$index => $param"; 

为了使这个模式更加可重用,在原始查询对象的原始SQL的注释中有一个很好的方法。

没有其他真正的查询,这是如何准备报表工作。 值绑定在数据库服务器中,而不是在应用程序层中。

看到我对这个问题的回答: 在PHP与PDO,如何检查最终的SQL参数化查询?

(这里为了方便重复:)

使用具有参数值的预准备语句不是简单地另一种dynamic创buildSQLstring的方法。 您在数据库中创build一个准备好的语句,然后单独发送参数值。

那么可能发送到数据库的将是PREPARE ... ,然后是SET ... ,最后是EXECUTE ....

你将无法像SELECT * FROM ...那样得到一些SQLstring,即使它会产生相同的结果,因为没有这样的查询实际上被发送到数据库。

我已经创build了一个Doctrine2 Logger来完成这个工作。 它使用Doctrine 2自己的数据types转换器“保存”参数化的sql查询。

 <?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; } } 

用法示例: 下面的和平代码将在标准输出上回显由$ em Entity Manager生成的任何INSERT,UPDATE,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 ) ) ); 

更明确的解决scheme

  /** * 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,则可以使用Workbench来查看正在运行的SQL语句。 您也可以使用以下命令查看来自mysql的正在运行的查询:

  SHOW FULL PROCESSLIST \G 

我的解决scheme

  /** * 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('Ymd 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 (:?) :?)中的参数通常是嵌套数组。

同时,如果你find了另一种方法,请友善地与我们分享:)

谢谢!

也许这可能对某人有用:

 // 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); 

我写了一个简单的logging器,它可以logging带有插入参数的查询。 安装:

 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; 

要在Doctrine中输出一个SQL查询,使用:

 $query->getResult()->getSql();