[php] 교리-준비된 진술뿐만 아니라 실제 SQL을 인쇄하는 방법?

우리는 PHP ORM 인 Doctrine을 사용하고 있습니다. 다음과 같은 쿼리를 작성 중입니다.

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

그런 다음 함수에서 다음과 같이 다양한 where 절과 사물을 적절하게 추가합니다.

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

나중에 execute()쿼리 개체를 가져 오기 전에 원시 SQL을 인쇄하여 검사하고 다음을 수행하려고합니다.

$q->getSQLQuery();

그러나 전체 쿼리가 아닌 준비된 명령문 만 인쇄합니다. 나는 그것이 MySQL로 무엇을 보내고 있는지보고 싶지만 대신을 포함하여 준비된 진술을 인쇄하고 ?있습니다. ‘전체’쿼리를 볼 수있는 방법이 있습니까?



답변

교리는 데이터베이스 서버에 “실제 SQL 쿼리”를 보내지 않습니다. 실제로 준비된 명령문을 사용하고 있습니다.

  • 진술서를 준비하여 보내십시오 (이것이 반환하는 것입니다 $query->getSql())
  • 그런 다음 매개 변수를 보내십시오 (로 반환 $query->getParameters())
  • 그리고 준비된 문장을 실행

이는 PHP 측에 “실제”SQL 쿼리가 없다는 것을 의미하므로 Doctrine은이를 표시 할 수 없습니다.


답변

실제 예 :

$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/query-log.html

당신이 찾고있는 것뿐만 아니라 더 많은 쿼리가있을 것입니다.

그러나 일반적으로 ->getSql();작동

편집하다:

내가 사용하는 모든 mysql 쿼리를 보려면

sudo vim /etc/mysql/my.cnf 

그 두 줄을 추가하십시오 :

general_log = on
general_log_file = /tmp/mysql.log

mysql을 다시 시작하십시오.


답변

정확히 이것을 수행하는 Doctrine2 Logger를 만들었습니다. 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;
    }
}

사용 예 :; 다음 코드는 $ 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
                        )
                    )
                );


답변

getSqlQuery() 기술적으로 전체 SQL 명령을 표시하지만 매개 변수를 볼 때 훨씬 유용합니다.

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

이 패턴의 재사용 성을 높이기 위해 Doctrine Query Object의 Raw SQL 주석 에 설명 된 멋진 접근 방식이 있습니다.


답변

다른 실제 쿼리는 없으며 준비된 명령문이 작동하는 방식입니다. 값은 응용 프로그램 계층이 아닌 데이터베이스 서버에 바인딩됩니다.

이 질문에 대한 나의 대답을보십시오 : PDO가있는 PHP에서 최종 SQL 매개 변수화 쿼리를 확인하는 방법은 무엇입니까?

(편의를 위해 여기에 반복됨)

매개 변수 값이있는 준비된 명령문을 사용하는 것은 단순히 SQL 문자열을 동적으로 작성하는 다른 방법이 아닙니다. 데이터베이스에서 준비된 명령문을 작성한 후 매개 변수 값만 보내십시오.

그래서 아마 데이터베이스로 전송하면됩니다 PREPARE ...다음, SET ...마지막으로EXECUTE ....

SELECT * FROM ...같은 쿼리가 실제로 데이터베이스로 전송되지 않았기 때문에 동등한 결과를 생성하더라도 SQL과 같은 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());