Php 条令-如何打印出真正的sql,而不仅仅是准备好的语句?
我们正在使用Doctrine,一种PHP ORM。我正在创建如下查询:Php 条令-如何打印出真正的sql,而不仅仅是准备好的语句?,php,mysql,orm,doctrine,doctrine-query,Php,Mysql,Orm,Doctrine,Doctrine Query,我们正在使用Doctrine,一种PHP ORM。我正在创建如下查询: $q = Doctrine_Query::create()->select('id')->from('MyTable'); 然后在函数中,我添加了各种where子句和适当的东西,比如 $q->where('normalisedname = ? OR name = ?', array($string, $originalString)); 稍后,在execute()-ing该查询对象之前,我想打印出原始S
$q = Doctrine_Query::create()->select('id')->from('MyTable');
然后在函数中,我添加了各种where子句和适当的东西,比如
$q->where('normalisedname = ? OR name = ?', array($string, $originalString));
稍后,在execute()
-ing该查询对象之前,我想打印出原始SQL以检查它,并执行以下操作:
$q->getSQLQuery();
但是,它只打印出准备好的语句,而不是完整的查询。我想看看它发送给MySQL的是什么,但是它打印出了一条准备好的语句,包括
?
。有什么方法可以查看“完整”查询吗?没有其他真正的查询,这就是预处理语句的工作方式。这些值在数据库服务器中绑定,而不是在应用程序层中绑定
见我对这个问题的回答:
(为方便起见,此处重复:)
使用带有参数化值的准备语句不仅仅是动态创建SQL字符串的另一种方法。在数据库中创建一个准备好的语句,然后单独发送参数值
因此,发送到数据库的可能是一个准备…
,然后设置…
,最后执行…
您将无法从…获取一些SQL字符串,如SELECT*FROM…
,即使它会产生相同的结果,因为实际上从未将此类查询发送到数据库
条令并没有向数据库服务器发送“真正的SQL查询”:它实际上使用的是准备好的语句,这意味着:
- 发送语句以准备它(这是由
$query->getSql()返回的)
- 然后,发送参数(由
返回)$query->getParameters()
- 以及执行准备好的语句
这意味着PHP端从来没有“真实”的SQL查询,因此,Doctrine无法显示它。如果您将所有查询记录在mysql中,您可以检查应用程序执行的查询: 将会有更多的查询,不仅是你正在寻找的查询,而且你可以通过grep查询 但通常是
->getSql()代码>工作
编辑:
查看我使用的所有mysql查询
sudo vim /etc/mysql/my.cnf
并添加这两行:
general_log = on
general_log_file = /tmp/mysql.log
重新启动mysqlgetSqlQuery()
从技术上讲确实显示了整个SQL命令,但是当您也可以看到参数时,它会更有用
echo $q->getSqlQuery();
foreach ($q->getFlattenedParams() as $index => $param)
echo "$index => $param";
为了使此模式更易于重用,at中介绍了一种很好的方法。一个工作示例:
$qb = $this->createQueryBuilder('a');
$query=$qb->getQuery();
// SHOW SQL:
echo $query->getSQL();
// Show Parameters:
echo $query->getParameters();
也许它对某人有用:
// 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;
我已经创建了一个Doctrine2记录器,它正是这样做的。它使用Doctrine 2自己的数据类型转换器将参数化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;
}
}
更明确的解决方案:
/**
* 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);
}
/**
* 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;}
解决方案:1
====================================================================================
函数showQuery($query)
{
返回sprintf(str_replace('?','%s',$query->getSql(),$query->getParams());
}
//调用函数
echo showQuery($doctrinequiry);
解决方案:2
====================================================================================
函数showQuery($query)
{
//定义变量
$output=NULL;
$out\u query=$query->getSql();
$out_param=$query->getParams();
//替换参数
对于($i=0;$i),您可以使用:
$query->getSQL();
如果您使用的是MySQL,那么可以使用Workbench查看正在运行的SQL语句。
您还可以使用以下命令从mysql查看正在运行的查询:
SHOW FULL PROCESSLIST \G
我的解决方案:
/**
* 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);
}
/**
* 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;}
要在Doctrine中打印SQL查询,请使用:
$query->getResult()->getSql();
您可以使用以下方法轻松访问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_值
和$col_名称
,则可以获得通过sql和相应列名传递的参数值
注意:如果$param
返回一个数组,则需要重新迭代,因为(:?)
中的中的参数通常作为嵌套数组出现
同时,如果您找到另一种方法,请与我们分享:)
谢谢!我编写了一个简单的记录器,它可以用插入的参数记录查询。
安装:
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;
修改了@dsamblas函数,使其在参数为类似“2019-01-01”的日期字符串以及使用类似的
$qb->expr()->in('ps.code', ':activeCodes'),
。因此,请按照dsamblas编写的所有操作进行操作,但请使用此操作替换startQuery,或者查看差异并添加我的代码。(以防他修改了其函数中的某些内容,而我的版本没有修改)
没有进行太多测试。TL;DR
$qb = ... // your query builder
$query = $qb->getQuery();
// temporarily enable logging for your query (will also work in prod env)
$conf = $query->getEntityManager()->getConnection()->getConfiguration();
$backupLogger = $conf->getSQLLogger();
$logger = new \Doctrine\DBAL\Logging\DebugStack();
$conf->setSQLLogger($logger);
// execute query
$res = $query->getResult();
$conf->setSQLLogger($backupLogger); //restore logger for other queries
$params = [
'query' => array_pop($logger->queries) //extract query log details
//your other twig params here...
]
return $params; //send this to your twig template...
在细枝文件中,使用Doctrine的细枝帮助器过滤器:
// show raw query:
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)
// highlighted
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query(highlight_only = true) }}
// highlighted and formatted (i.e. with tabs and newlines)
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query }}
说明:
其他提到Prepared语句实际上是“真正的查询”的答案是正确的,但它们并没有回答提问者明显的期望……每个开发人员都希望显示一个“可运行的查询”以进行调试(或向用户显示)
因此,我查看了Symfony profiler的源代码,以了解他们是如何做到这一点的。条令部分是条令的责任,因此他们制作了一个条令包来与Symfony集成。查看条令包/Resources/views/Collector/db.html.twig
文件,您将了解他们是如何做到这一点的(这可能会在不同版本之间发生变化)有趣的是,他们创建了我们可以重用的树枝过滤器(见上文)
要使一切正常工作,我们需要为查询启用日志记录。有多种方法可以做到这一点,在这里我使用DebugStack,它允许记录查询而无需实际打印查询。这还可以确保这将在生产模式下工作,如果这是您需要的
如果您需要进一步格式化,您将看到它们在样式标记中包含一些CSS,因此只需“窃取”它^^:
希望,这会有所帮助;-)我为此主题做了一些研究,因为我想调试生成的SQL查询并在SQL编辑器中执行它。从所有答案中可以看出,这是一个技术性很强的主题
当我
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;
}
}
$qb = ... // your query builder
$query = $qb->getQuery();
// temporarily enable logging for your query (will also work in prod env)
$conf = $query->getEntityManager()->getConnection()->getConfiguration();
$backupLogger = $conf->getSQLLogger();
$logger = new \Doctrine\DBAL\Logging\DebugStack();
$conf->setSQLLogger($logger);
// execute query
$res = $query->getResult();
$conf->setSQLLogger($backupLogger); //restore logger for other queries
$params = [
'query' => array_pop($logger->queries) //extract query log details
//your other twig params here...
]
return $params; //send this to your twig template...
// show raw query:
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)
// highlighted
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query(highlight_only = true) }}
// highlighted and formatted (i.e. with tabs and newlines)
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query }}
.highlight pre { margin: 0; white-space: pre-wrap; }
.highlight .keyword { color: #8959A8; font-weight: bold; }
.highlight .word { color: #222222; }
.highlight .variable { color: #916319; }
.highlight .symbol { color: #222222; }
.highlight .comment { color: #999999; }
.highlight .backtick { color: #718C00; }
.highlight .string { color: #718C00; }
.highlight .number { color: #F5871F; font-weight: bold; }
.highlight .error { color: #C82829; }
$sql = $query->getSQL();
$obj->mapDQLParametersNamesToSQL($query->getDQL(), $sql);
echo $sql;//to see parameters names in sql
$obj->mapDQLParametersValuesToSQL($query->getParameters(), $sql);
echo $sql;//to see parameters values in sql
public function mapDQLParametersNamesToSQL($dql, &$sql)
{
$matches = [];
$parameterNamePattern = '/:\w+/';
/** Found parameter names in DQL */
preg_match_all($parameterNamePattern, $dql, $matches);
if (empty($matches[0])) {
return;
}
$needle = '?';
foreach ($matches[0] as $match) {
$strPos = strpos($sql, $needle);
if ($strPos !== false) {
/** Paste parameter names in SQL */
$sql = substr_replace($sql, $match, $strPos, strlen($needle));
}
}
}
public function mapDQLParametersValuesToSQL($parameters, &$sql)
{
$matches = [];
$parameterNamePattern = '/:\w+/';
/** Found parameter names in SQL */
preg_match_all($parameterNamePattern, $sql, $matches);
if (empty($matches[0])) {
return;
}
foreach ($matches[0] as $parameterName) {
$strPos = strpos($sql, $parameterName);
if ($strPos !== false) {
foreach ($parameters as $parameter) {
/** @var \Doctrine\ORM\Query\Parameter $parameter */
if ($parameterName !== ':' . $parameter->getName()) {
continue;
}
$parameterValue = $parameter->getValue();
if (is_string($parameterValue)) {
$parameterValue = "'$parameterValue'";
}
if (is_array($parameterValue)) {
foreach ($parameterValue as $key => $value) {
if (is_string($value)) {
$parameterValue[$key] = "'$value'";
}
}
$parameterValue = implode(', ', $parameterValue);
}
/** Paste parameter values in SQL */
$sql = substr_replace($sql, $parameterValue, $strPos, strlen($parameterName));
}
}
}
}