Udv!
Egy mysql query reszt kellene atalakitanom, de nem igazan boldogulok vele hatekony modon - meg mashogy sem :- ).
Az eredeti query igy nez ki:
rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')
es valami ilyesmit szeretnek kapni belole:
rep_platform LIKE '%VALAMI1%' or rep_platform LIKE '%VALAMI2%' or rep_platform LIKE 'VALAMI3'
.
Nyilvan az IN utani tombben levo elemek szama 1- tol n- ig valtozik (valami mindenkeppen van benne), es az aposztrofok kozotti resz NEM tartalmaz aposztrofot.
Koszi a valaszokat.
- 1089 megtekintés
Hozzászólások
my $query = < DATA >; # szóközöket vedd ki
# SPARTAAA style
chomp $query; # levágja az újsort a végéről
chop $query; # levágja a zárójelet a végéről
my @fields = split / IN \(|, /, $query; # szétszedi a sort
my $key = shift @fields; # az első mező külön változóba, a tömbben csak a VALAMIk maradnak
s/'//g for @fields; # leszedi a '-ket
# összeállítja az új lekérdezést
my $new_query = join ' or ', map {$key." LIKE '\%$_\%'"} @fields;
print $new_query.$/;
__DATA__
rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')
Sőt, ha úgy sincsenek '-k a VALAMIk belsejében, akkor:
my $query = < DATA >;
# double SPARTAAA style
chomp $query;
chop $query;
$query =~ tr/'//d;
my @fields = split / IN \(|, /, $query;
my $key = shift @fields;
my $new_query = join ' or ', map {$key." LIKE '\%$_\%'"} @fields;
print $new_query.$/;
__DATA__
rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')
- A hozzászóláshoz be kell jelentkezni
Ha a 'VALAMI' -ben van vessző, azt viszont még mindig beszopod:)
- A hozzászóláshoz be kell jelentkezni
Igaz, akkor legyen mondjuk:
$_ = < DATA >;
# triple SPARTAAA style
chomp;
chop;
chop;
split /\s+IN\s+\(\'|\',\s*\'/;
my $key = shift @_;
my $new_query = join ' or ', map {$key." LIKE '\%$_\%'"} @_;
print $new_query.$/;
__DATA__
rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')
- A hozzászóláshoz be kell jelentkezni
Too fragile. Ha itt-ott lenne még egy space, pl. a végén, a vessző előtt, ( és ' után, stb, máris nemjó.
De csak kötekszek, elhiszem hogy meg tudnád írni jól :)
- A hozzászóláshoz be kell jelentkezni
Ebben is igazad van, de valahol meg kell húzni a határt, nem lehet az összes elképzelhető hibalehetőséget lekezelni - előbb-utóbb a teljesítmény és az átláthatóság rovására menne.
Különben is, az OP-ban lévő specifikációt, ami áll egy darab példából ;), a megoldásom teljesíti.
Ha mondjuk ez egy éles alkalmazás lenne, ahol lehetne mintát venni az előforduló query-kből és az azokban előforduló hibás formázásokból, akkor be lehetne lőni, hogy meddig érdemes elmenni a megoldás általánosításával.
Na meg az se mindegy, hogy ezeket a stringeket a felhasználó viszi be, vagy eleve már valami generálja. Az előbbi eset a bonyolultabb, mert a felhasználók tényleg ördögien ügyesek, hogy a programozó által lekezelt n lehetséges rossz bevitelen felüli n+1-ediket is megtalálják (ez n tetszőleges értékére igaz).
- A hozzászóláshoz be kell jelentkezni
"valahol meg kell húzni a határt, nem lehet az összes elképzelhető hibalehetőséget lekezelni - előbb-utóbb a teljesítmény és az átláthatóság rovására menne"
the unix way :-)
- A hozzászóláshoz be kell jelentkezni
Tessek itt egy robosztusabb ;-)
Persze az ilyet szepen sql parserrel kene es nem regexppel parse-olni.
#! /usr/bin/perl
use strict;
use warnings;
while ( my $q = <DATA> ) {
$q =~ m/\A \s* rep_platform \s+ IN \s* \( \s* ([^)]*) \) \s* \z/xmsi;
my @args = map { substr $_, 1, -1 } split /\s*,\s*/, $1;
warn "warning: no args given" if ( not @args );
my $out = join q{ OR }, map {"rep_platform LIKE '\%$_\%'"} @args;
print $out, "\n";
}
__DATA__
rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')
- A hozzászóláshoz be kell jelentkezni
@_=split /'/, $_;
for (my $m=1; $m<scalar @_; $m+=2) { push @args, $_[$m]; }
- A hozzászóláshoz be kell jelentkezni
Szerintem jobban jársz, ha nem regexp-pel próbálkozol, hanem find-dal keresed meg az aposztrófokat, és két-két aposztróf közötti szövegből összerakosz részquery-ket, amit listába raksz és a végén összejoinolod.
- A hozzászóláshoz be kell jelentkezni
Kicsit megerőszakolás, kicsit lassú, de nem lehetetlen:
$str = q/rep_platform IN ('VALAMI1', 'VALAMI2', 'VALAMI3')/;
$str =~ s/(\w+)\s+in\s*//i;
$column = $1;
while (
$str =~ s/\(\s*'([^']+)'\)?/$column LIKE '%$1%'/i or
$str =~ s/\s*,\s*'([^']+)'\s*\)?/ or $column LIKE '%$1%'/g
) { }
print "$str\n";
- A hozzászóláshoz be kell jelentkezni
Lehet regexppel, de nem célszerű. Az ilyen capture-olós kifejezések lassúak - nyilván három elemnél nem fog számítani, de tízezernél már igen.
Arról nem is beszélek, hogy nehezebben olvasható a megoldásod, mint a fenti, split-join alapú.
- A hozzászóláshoz be kell jelentkezni
Persze, mindezen tualjdonságokat meg is előlekeztem a "megerőszakolás" és "lassú" kitételekkel, de ez utóbbinak most utána is jártam.
10, 100, ..., 100000 elemű in-listákat tartalmazó fájlokat konvertáltam át like-ossá a fenti kóddal. Az eredmény nem sokkoló, ill. annyiban, hogy bár a futási idő kb. egyenes arányban nő a 10-szerezésekkor, de még így is bakfitty egy nem túl friss (T43p) notebookon:
100000.sql:
real 0m0.236s
user 0m0.212s
sys 0m0.024s
-------
10000.sql:
real 0m0.026s
user 0m0.028s
sys 0m0.000s
-------
1000.sql:
real 0m0.005s
user 0m0.004s
sys 0m0.000s
-------
100.sql:
real 0m0.003s
user 0m0.000s
sys 0m0.004s
-------
10.sql:
real 0m0.002s
user 0m0.000s
sys 0m0.000s
-------
- A hozzászóláshoz be kell jelentkezni