好的,这是我的测试(这不是生产代码,只是一个测试来说明我的问题)
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的最后一次出现?)(实际上,模式更复杂,但没关系).
有任何想法吗?
解决方法
为什么要通过硬编码字符串然后对它们进行替换来构建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.例如,考虑选择… where user.name =’where’.