好的,这是我的测试(这不是生产代码,只是用来说明我的问题的测试)
my $string = <<EOS; # auto generated query
SELECT
users.*
, roles.label AS role_label
, hr_orders.position_label
, deps.label AS dep_label
, top_deps.label AS top_dep_label
FROM
users
LEFT JOIN $conf->{systables}->{roles} AS roles ON users.id_role = roles.id
LEFT JOIN (
SELECT
id_user
, MAX(dt) AS max_dt
FROM
hr_orders
WHERE
fake = 0
AND
IFNULL(position_label, ' ') <> ' '
GROUP BY id_user
) last_hr_orders ON last_hr_orders.id_user = users.id
LEFT JOIN hr_orders ON hr_orders.id_user = last_hr_orders.id_user AND hr_orders.dt = last_hr_orders.max_dt
$join
WHERE
$filter
ORDER BY
$order
$limit
EOS
my $where = "WHERE\nusers.fake = -1 AND ";
$string =~ s{where}{$where}i;
print "result: \n$string";
生成查询的代码以简单的s {where} {$ where} i结尾,它取代了每次出现的地方。
我想用'WHERE users.fake = -1'替换顶级WHERE(WHERE的最后一次出现?)(实际上,模式更复杂,但没关系)。
有什么想法吗?
答案 0 :(得分:3)
为什么要通过对字符串进行硬编码然后对其进行替换来构建sql查询?不会像
那样my $proto_query = <<'EOQ'
select ... where %s ...
EOQ
my $query = sprintf $proto_query, 'users.fake = -1 AND ...';
或(最好,因为它避免了您的初始方法和上述方法中的许多问题)使用Data::Phrasebook::SQL
这样的模块可以使很多事情变得更容易?
如果你真的想进行字符串替换,你可能正在寻找像
这样的东西my $foo = "foo bar where baz where moo";
$foo =~ s/(.*)where/$1where affe and/;
say $foo; # "foo bar where baz where affe and moo"
也就是说,尽可能多地捕捉,直到你无法捕捉到任何更多但没有“在哪里”立即跟随你捕获的内容,然后再插入你捕获的任何捕获的内容,以及你想做的任何修改。
但是,请注意,如果您使用它来破坏SQL查询,则会有各种限制。要做正确的事,你必须在某种程度上真正理解SQL。例如,考虑select ... where user.name = 'where'
。
答案 1 :(得分:2)
答案 2 :(得分:2)
解析SQL查询的正确方法是使用解析器而不使用正则表达式。
参见 SQL::Statement::Structure - 解析并检查SQL查询的结构