Página 1 de 1

Uso de la función to_number

NotaPublicado: 2012-07-10 13:56 @622
por reLlene
Dentro de un
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. foreach $id (keys %hash)
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
quiero realizar una consulta a una DB (Postgresql). La consulta que quiero realizar es "semejante" a la siguiente (y digo semejante porque no me está resultando):

Sintáxis: [ Descargar ] [ Ocultar ]
Using sql Syntax Highlighting
  1. SELECT * FROM tabla WHERE pres = 3 AND length(codigo)>0 AND codigo ~ ^[0-9]+$ AND $id = to_number('codigo', '999999');
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


En dónde pongo length(código)>0 la intención es que la longitud del contenido de código sea mayor a cero, lo aclaro por las dudas.

En dónde pongo código ~ ^[0-9]+$ quiero decir que los caracteres comienzan y terminan con dígitos y la palabra más corta ser un solo dígito o más...

Y por último to_number es una función que permite transformar el contenido de cada uno de los códigos en dígitos y de esa manera ver si coincide con el valor de la variable $id. Por ejemplo 2563=2563// y esto DAR TRUE porque corresponde exceptuando el resto... donde $id=2563 y código=2563.

Una última aclaración: miré un poco el contenido de la tabla y los contenidos de código, pueden ser:
0
xxx
xxxxxxx
asdqwe
No corresponde
000000
10787//
1111111
-
17321 ab tvf
RT CASONA


En la tabla, código es VARCHAR y la variable $id (del script Perl) siempre numérica.

¡¡¡Agradecería a quien sea por alguna mano!!!

Re: Uso de la función to_number

NotaPublicado: 2012-07-10 17:28 @769
por explorer
¿Y hacer un simple SELECT * para bajar todos los datos a Perl y que sea Perl el que haga el filtrado?

Re: Uso de la función to_number

NotaPublicado: 2012-07-10 21:45 @948
por reLlene
¡Humm... interesante! Pero se trata de una tabla con más de 100 000 registros, de eso estoy seguro y creo que puede llegar a traer problemas, incluso a la hora de actualizarse la misma, el script SIEMPRE estará obligado a bajarlo todo y después filtrar :?

Re: Uso de la función to_number

NotaPublicado: 2012-07-11 05:16 @261
por explorer
reLlene escribiste:¡Humm... interesante! Pero se trata de una tabla con más de 100 000 registros, de eso estoy seguro
Yo he hecho eso mismo con tablas de casi tres millones.

reLlene escribiste:y creo que puede llegar a traer problemas,
Tuvimos problemas de memoria, pero se arreglaron cuando quitamos el Windows y pusimos Linux en todas las máquinas.

reLlene escribiste:incluso a la hora de actualizarse la misma,
La actualización es labor de INSERT y UPDATE, no de los SELECT.

reLlene escribiste:el script SIEMPRE estará obligado a bajarlo todo y después filtrar :?
Igual que siempre que haces una consulta a una base de datos. ¿No es eso lo que hace una consulta a una base de datos? Necesitas sacar una información, pues entonces necesitas construir la mejor consulta para que el motor de base de datos saque lo que necesites. Otra opción es hacer la consulta una vez, guardar toda la información en memoria, y hacer que el programa no termine nunca. O guardar la consulta en un archivo fácil y rápido de recuperar (disco RAM, por ejemplo).

Desde luego, si conseguimos construir una buena consulta, el motor de la base de datos puede llegar a ser más rápido que cualquier programa (no siempre es así, pero es -debería ser- lo normal).

Ahora bien, hay ocasiones en las que el proceso de filtrado lo puede realizar mejor el programa que el motor de la base de datos. En el caso mío, fue así: Había que relacionar los campos de una tabla de dos millones de registros con los de otra tabla con un millón. Leyendo los tres millones de datos, y metiéndolos en un hash en Perl, era mucho más rápido que lo tardaba el motor de búsqueda haciendo JOIN entre las tablas.

Es cuestión de hacer pruebas y medir los tiempos de respuesta, naturalmente.

Así que la cuestión sigue centrada en la consulta. Según lo que pones, parece que lo estás haciendo bien porque compruebas todos los casos ($código contiene algo, $código son solo dígitos y comparas $id con la conversión a numero de $código).

¿No valdría con un simple

SELECT * FROM tabla WHERE pres = 3 AND codigo LIKE '$id';

?

Edito: cambiado el orden de los parámetros en la consulta.

Re: Uso de la función to_number

NotaPublicado: 2012-07-13 21:14 @926
por reLlene
Finalmente he seguido tu consejo utilizando la función like y paso un poco en limpio la labor a ver si estoy haciendo bien las cosas:

Me descargo de un sitio concreto toda la información, esta información tiene algo como la siguiente forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
id      | Apellido, Nombre  | calle           | telefono
4564  |Marza, Luis Alberto | Avenida Los pozos | 4785-6544
...
...
...
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Luego procedo a guardar en un hash, toda esta información, en forma de registros.

Una vez que me las cargo en el hash, utilizo el foreach() para comparar TODOS esos registros (de hecho son clientes, porque un registro es un cliente) con otros registros que yo tengo en una base de datos (postgresql) que tienen un campo "codigo" (que es aquél que mencione en mi publicación) que coincide o NO con el id.

Si éstos coinciden, es decir id (del sitio) es igual a codigo (de mi DB) entonces los "capturo". Ahora, si no, tengo que emplear distintas reglas para "capturar "(NUEVAMENTE) y "capturar"(NUEVAMENTE) desde mi DB, porque codigo en mi DB es VARCHAR, entonces pueden existir códigos, pueden ser miles de cosas...

Ahora, lo FEO de esto es que hay muchísimos if() anidados, muchos, pero muchos y la cosa resulta bien porque FUNCIONA, pero... ¿a alguien se le ocurre otra forma de filtrar más rápidamente y de forma más legible estos campos?

Re: Uso de la función to_number

NotaPublicado: 2012-07-14 09:27 @435
por explorer
Si las "reglas" se pueden expresar en forma de expresiones regulares, se puede abreviar bastante, desde luego.

Si pones algunos ejemplos de esas reglas, lo sabremos.

Re: Uso de la función to_number

NotaPublicado: 2012-07-14 16:17 @720
por reLlene
Bien, el campo 'codigo' de la tabla puede llegar a ser, cualquiera de las siguientes:
0
xxx
xxxxxxx
asdqwe
No corresponde
000000
10787//
1111111
-
17321 ab tvf
RT CASONA
*********
Ver observaciones
--
titular
SIN CGP
no lo tiene
Cliente 16383
-----
no es cliente
titular rt casona


TODOS estos los saco con la siguiente expresión regular:
codigo ~ '^[a-z_ A-Z0-9]+\$'

Ahora, los siguiente ya no los logro sacar:
abonado: 32564
DNI.: 16832130
DNI.:16832130
- éste sin espacio después del ':' -
(no es cliente)
8561(Martin, Alejandro Javier)


y son los últimos que me están faltando (o al menos de momento, los otros, como dije los estoy pudiendo capturar con la regexp de arriba).

Re: Uso de la función to_number

NotaPublicado: 2012-07-14 17:17 @761
por explorer
reLlene escribiste:Ahora, los siguiente ya no los logro sacar:
abonado: 32564
DNI.: 16832130
DNI.:16832130
- éste sin espacio después del ':' -
[b](no es cliente)
8561(Martin, Alejandro Javier)

Bueno, pero ¿la cuestión es reducir todos los casos a un solo patrón de expresiones regulares?

Sigo sin entender muy bien el proceso que haces. Dices que tienes un montón de if() en cascada. Entonces, para "capturar" esos casos solo tienes que añadir más if().

Lo que no entiendo es por qué hablas de la expresión regular de la sentencia SQL. ¿Es que estás ejecutando sentencias SQL por cada caso? Si son muchos casos, entonces sí que merece la pena leer toda la información a memoria.

¿No puedes poner un trozo de código que muestre el proceso de captura de uno o dos casos?

Re: Uso de la función to_number

NotaPublicado: 2012-07-17 01:04 @086
por reLlene
La cuestión es optimizar un poco la expresión regular de forma tal que capture una (o pocas) formas. Sin tener que aplicar muchos filtros como estos y tantos otros. O bien, leer TODA la información a memoria como tú dices pero es que no entiendo o no me lo imagino cómo hacerlo...

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.             # No encontré por nombre
  2.             # BUSCO por codigocgp IGUAL A "0"
  3.  
  4.             $query = "SELECT rid FROM tabla
  5.                                  WHERE codigo ='0'";
  6.             my ( $r, $scrid ) = Select1SSQL($query);
  7.             if ($scrid) {
  8.                 $totalEncontradosSolicitudesConCero++;
  9.                 $query2 = "SELECT nombre, direccion, estado
  10.                                         FROM tabla2
  11.                                         WHERE sc.rid = $scrid";
  12.                 my ( $s, @cero ) = SelectSSQL($query2);
  13.                 if ( $cero[2] == "0" ) {    #para ver si su estado es ok o no
  14.                     print "OK => ";
  15.                     print join "|", @cero;
  16.                     print "\n";
  17.                 }
  18.                 else {
  19.                     print "PB => ";
  20.                     print join "|", @cero;
  21.                     print "\n";
  22.                     $pb++;
  23.                 }
  24.             }                          #no encuentra por codigocgp IGUAL a cero
  25.             else {                     # BUSCO por codigocgp IGUAL a null
  26.                 $query3 = "SELECT rid FROM tabla
  27.                                                         WHERE codigo IS NULL";
  28.                 my ( $t, $scrid ) = SelectSSQL($query3);
  29.                 if ($scrid) {
  30.                     $totalEncontradosSolicitudesConNull++;
  31.                     $query4 = "SELECT nombre, direccion, estado
  32.                                                 FROM tabla2  
  33.                                                 WHERE sc.rid = $scrid4";
  34.                     my ( $u, @null ) = Select1SSQL($query4);
  35.                     if ( $null[2] == "0" ) {
  36.                         print "OK => ";
  37.                         print join "|", @null;
  38.                         print "\n";
  39.                     }
  40.                     else {
  41.                         print "PB => ";
  42.                         print join "|", @null;
  43.                         print "\n";
  44.                         $pb++;
  45.                     }
  46.                 }
  47.             }                          #else{
  48.                                        #y así, sucesivamente voy aplicando filtro tras otro filtro...
  49.  
  50.             #}
  51.  
  52.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Como se ve, la cosa sigue así en unos cuantos otros else y aquellos códigos que desconocía hasta hace unos días como capturar (me refiero a los siguientes), los he capturado así:

abonado: 32564 # codigo ~ '^[a-z_ :0-9]+\$'
DNI.: 16832130 # codigo LIKE '%DNI%'
DNI:15446678887 # igual que el de arriba
(no es cliente) # codigo ~ '(no es cliente)';
8561(Martin, Alejandro Javier) # codigo = '8561 (Martin, Wiliams Jose)'

Re: Uso de la función to_number

NotaPublicado: 2012-07-17 06:57 @331
por explorer
Hay código que está repetido, o casi, por lo que es aspirante a ser resumido en un único procedimiento.

Por ejemplo, el código que hay entre las líneas 6 y 23 son las mismas que hay entre 28 y 46, salvo que en la segunda parte hay un $scrid4 en lugar de un $scrid.

Y ese código común hace lo mismo: una consulta a la base de datos. Visto así, parece que sí merece la pena hacer una sola consulta y guardar la información en un array de array. O si estamos seguros de que las claves son únicas (y así parece porque las consultas que haces solo devuelven una fila de resultado), en un hash de array: cada clave del hash será el 'sc.rid', y valor será un array anónimo que almacena los valores de 'nombre', 'direccion' y 'estado'.

Incluso si no puedes reducir todos los casos a un código común, se puede poner en forma de subrutina, pasando los argumentos que varían de uno a otro caso.

Ejemplo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my($t, $scrid ) = SelectSSQL("SELECT rid FROM tabla WHERE codigo ='0'");
  2.  
  3. if ($scrid) {
  4.     $totalEncontradosSolicitudesConCero++;
  5.     analiza($scrid);
  6. }
  7. else {
  8.     my($t, $scrid ) = SelectSSQL("SELECT rid FROM tabla WHERE IS NULL");
  9.     $totalEncontradosSolicitudesConNull++;
  10.     analiza($scrid);
  11. }
  12.  
  13. # ...
  14.  
  15. sub analiza {
  16.     my($id) = shift;
  17.     my($u, @null) = Select1SSQL("SELECT nombre, direccion, estado FROM tabla2 WHERE sc.rid = $id");
  18.  
  19.     if ( $null[2] == 0 ) {
  20.         print 'OK => ';
  21.     }
  22.     else {
  23.         print 'PB => ';
  24.         $pb++;
  25.     }
  26.     print join('|', @null), "\n";
  27. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Incluso se puede reducir más, si las variables de totales las convertimos en miembros de un hash:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %consultas = (
  2.     'ConCero'  => "SELECT rid FROM tabla WHERE codigo ='0'",
  3.     'ConNull'  => "SELECT rid FROM tabla WHERE IS NULL",
  4. );
  5.  
  6. my %total;
  7.  
  8. for my $consulta (keys %consultas) {
  9.     print "Haciendo consulta $consulta\n";
  10.     my($t, $scrid ) = SelectSSQL($consultas{$consulta});
  11.  
  12.     if ($scrid) {
  13.         $total{$consulta}++;
  14.         analiza($scrid);
  15.     }
  16. }
  17.  
  18. # ...
  19.  
  20. sub analiza {
  21.     my($id) = shift;
  22.     my($u, @null) = Select1SSQL("SELECT nombre, direccion, estado FROM tabla2 WHERE sc.rid = $id");
  23.  
  24.     if ( $null[2] == 0 ) {
  25.         print 'OK => ';
  26.     }
  27.     else {
  28.         print 'PB => ';
  29.         $pb++;
  30.     }
  31.     print join('|', @null), "\n";
  32. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

De esta manera, el código queda muy reducido. Para meter más consultas solo tienes que ampliar %consultas. Y los resultados quedan reunidos dentro del hash %total.

La otra opción es hacer una consulta a tabla2 para recuperar toda la información y meterla en un array o hash, y así nos ahorramos el hacer muchas consultas dentro de analiza(). Solo tendríamos que buscar si existe algún código coincidente con lo que buscamos (con un bucle en el caso de un array o de forma directa si es un hash).