Perl error при передаче DBI-> выполнить значения для предложения IN

У меня есть запрос для вычисления объектов, находящихся в определенном радиусе точки на основе документа здесь: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

Это работает очень хорошо, однако я хочу искать только те объекты, которые имеют определенный тип, и это вызывает проблему;

Код выглядит так:

my $sql = "SELECT * FROM ( SELECT b.*, pr.postcode, pr.prize, pr.title, pr.collection, pr.redeemed, pr.delivery, pr.archived, bt.category, p.radius, p.distance_unit * DEGREES(ACOS(COS(RADIANS(p.latpoint)) * COS(RADIANS(b.lat)) * COS(RADIANS(p.longpoint - b.lng)) + SIN(RADIANS(p.latpoint)) * SIN(RADIANS(b.lat)))) AS distance FROM bubbles AS b, bubble_prizes AS pr, bubble_types AS bt JOIN ( /* these are the query parameters */ SELECT ? AS latpoint, ? AS longpoint, ? AS radius, ? AS distance_unit ) AS p WHERE b.lat BETWEEN p.latpoint - (p.radius / p.distance_unit) AND p.latpoint + (p.radius / p.distance_unit) AND b.lng BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint)))) AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint)))) AND pr.bubble = b.id AND b.type IN ? AND b.type = bt.type ) AS d WHERE distance <= radius ORDER BY distance";

Я тогда делаю

my $points = $y->dbh->prepare($sql);
$results = $points->execute($lat, $lng, $rad, $units, '(type1, type2)');

где '(type1, type2)' должно быть передано

b.type IN ?

(который находится в нижней части SQL).

Я пробовал все, что мог придумать, чтобы избежать этой строки, чтобы она работала (включая множество способов, которые явно безумны, но я отчаянно)

'(type1, type2)'
'\(\'type1\', \'type2\'\)'
'(\'type1\', \'type2\')'
"('type1', 'type2')"

и т.д. (я пробовал так много вещей, о которых я даже не могу запомнить).

Независимо от того, что я пытаюсь, я получаю SQL-ошибку формы

DBD::mysql::st execute failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''(type1, type2)' AND b.type = bt.type ) AS d WHERE distance <= radius'

В зависимости от того, как я пытался избежать строки, сообщение об ошибке несколько отличается, но всегда относится к той же части sql.

Теперь я думаю, что побег - это не моя проблема, и я пропускаю что-то о выполнении. Если я запускаю код в БД, он отлично работает с обычным IN-выражением iebtype IN ('type1', 'type2') работает нормально.

Может кто-нибудь просветить меня? Как я должен это делать?

благодаря

1 ответ

Вам нужно будет использовать заполнители в инструкции IN (...). Вся задача execute() заключается в том, чтобы избежать SQL-инъекции, и вы в основном пытаетесь внедрить SQL там. Вы можете сделать динамический список заполнителей следующим образом:

my @types = qw(type1 type2);
my $placeholders = join ", ", ("?") x @types;
my $sql = "... b.typeID IN ($placeholders) ...";
my $points = $y->dbh->prepare($sql);
$results = $points->execute($lat, $lng, $rad, $units, @types);

licensed under cc by-sa 3.0 with attribution.