Как использовать параметр внутри цитаты в Postgres? Я все время получаю ошибку: "SQLSTATE[HY093]: Invalid parameter number: :beginDaysAgo"
Когда мы смотрим на эти строки:
WHERE a.balance <= (a.autorefill_threshold+:amountAboveThreshold)
AND ((t.created_at <= ( current_timestamp-INTERVAL \':beginDaysAgo days\')) AND ( t.created_at >= (current_timestamp) - INTERVAL \':totalDays days\'))
Первый параметр не вызывает у меня ошибки. Это те, что внутри цитаты.
Это означает, что первый параметр, amountAboveThreshold, работает, но явно не может выполнять поиск в строке.
По сути, когда я просто использую переменную PHP внутри вместо параметра, она работает отлично, или когда я просто ввожу число. Так, например, когда я помещаю число 20, а затем 21 для этих двух параметров, beginDaysAgo и totalDays соответственно работает отлично.
Но когда я пытаюсь использовать параметры - а это правильный и безопасный способ сделать это - это не работает.
public function getClientsWithBalanceBelowThreshold(
$amountAboveThreshold=100.00,
$beginDaysAgo = 0,
$amountOfDays = 1
) {
$totalDays = $amountOfDays + $beginDaysAgo;
//this one works
if ((double)$amountAboveThreshold!=$amountAboveThreshold)
throw new \TypeError("Type Mismatch");
$conn = $this->em->getConnection();
$conn = $this->em->getConnection();
$sql = '
SELECT DISTINCT ON (l.public_id) a.balance, a.public_id as account_public_id, a.organization_name, a.autorefill_threshold,
l.name as listing_name, l.paused, l.public_id,
t.balance_before,
t.balance_after, t.created_at, t.type
FROM transaction as t INNER JOIN account a
ON t.account_id = a.account_id
INNER JOIN listing as l ON a.account_id = l.account_id
WHERE a.balance <= (a.autorefill_threshold+:amountAboveThreshold)
AND ((t.created_at <= ( current_timestamp-INTERVAL \':beginDaysAgo days\')) AND ( t.created_at >= (current_timestamp) - INTERVAL \':totalDays days\'))
AND t.balance_before != t.balance_after
AND t.type != \'credit\'
ORDER BY l.public_id, a.balance DESC, t.created_at, l.account_id;
';
$stmt = $conn->prepare($sql);
$stmt->bindParam('amountAboveThreshold', $amountAboveThreshold);
$stmt->bindParam('beginDaysAgo', $beginDaysAgo);
$stmt->bindParam('totalDays', $totalDays);
$stmt->execute();
var_dump($stmt->fetchAll());die;
Я получаю полную ошибку ...
"SQLSTATE[HY093]: Invalid parameter number: :beginDaysAgo" #0 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/doctrine/db al/lib/Doctrine/DBAL/Statement.php(141): Doctrine\DBAL\Driver\PDOStatement->bindParam('beginDaysAgo', '18', 2, NULL)
#1 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/src/Rb/ReportingApiBundle/ClientThreshold/ClientBelowThresholdReport.php(77): Doctrine\DBAL\Statement->bindParam('beginDaysAgo', '18')
#2 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/src/Rb/ReportingApiBundle/Command/ClientBelowThresholdReportCommand.php(61): Rb\ReportingApiBundle\ClientThreshold\ClientBelowThresholdReport->getClientsWithBalanceBelowThreshold('120.00', '18', '2')
#3 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php(259): Rb\ReportingApiBundle\Command\ClientBelowThresholdReportCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#4 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(863): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#5 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(192): Symfony\Component\Console\Application->doRunCommand(Object(Rb\ReportingApiBundle\Command\ClientBelowThresholdReportCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#6 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(92): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#7 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(123): Symfony\Bundle\FrameworkBundle\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#8 /var/www/clientreachapi.com/releases/2018_03_10_14_54_58/app/console(29): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput))
#9 {main}






Я думаю, что когда у вас есть :beginDaysAgo и :totalDays, указанные в запросе, они будут интерпретироваться как буквальные строки, а не как заполнители для параметров. Я бы предложил удалить кавычки и часть days из SQL и оставить только заполнители, например:
(t.created_at <= (current_timestamp - INTERVAL :beginDaysAgo))
AND ( t.created_at >= (current_timestamp - INTERVAL :totalDays))
А затем добавляем часть days к числовым значениям, прежде чем связывать их с подготовленным оператором:
$beginDaysAgo = "$beginDaysAgo days";
$amountOfDays = "$amountOfDays days";
@jcaron Да, я думал, что что-то подобное тоже может сработать, но я недостаточно уверен в postgres, чтобы предложить конкретный способ.
Или, может быть, выполнить конкатенацию в SQL, например, с помощью
||(не пробовал)