Archivos de Categoría: MySQL - Paginas 4

Calcular distancias entre puntos geoposicionados con MySQL

Me ha tocado montar un buscador mostrando la distancia entre dos puntos geoposicionados así que googleando un poco me he encontrado con esta función que va bastante bien:

CREATE FUNCTION `geodistkm`(
        lat1  FLOAT ,
        lon1  FLOAT,
        lat2 FLOAT ,
        lon2 FLOAT
    )
    RETURNS float
    NOT DETERMINISTIC   
BEGIN
	 DECLARE pi, q1, q2, q3 FLOAT;
	 DECLARE rads FLOAT DEFAULT 0;
	 SET pi = PI();
	 SET lat1 = lat1 * pi / 180;
	 SET lon1 = lon1 * pi / 180;
	 SET lat2 = lat2 * pi / 180;
	 SET lon2 = lon2 * pi / 180;
	 SET q1 = COS(lon1-lon2);
	 SET q2 = COS(lat1-lat2);
	 SET q3 = COS(lat1+lat2);
	 SET rads = ACOS( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) ); 
	 RETURN 6378.388 * rads;
END;

Comparar dos cadenas en MySQL con posibles valores null

En un proceso de importación que acabo de terminar de montar, me toca comprobar si un usuario está registrado y como no tenemos DNI toca hacerlo comprobando si el nombre y los apellidos coinciden. No es que sea muy de fiar pero el cliente es lo que pide….
El problema es que el nombre y los apellidos están en tres campos distintos por lo que toca concatenarlos.

SELECT CONCAT(NOMBRE,APELLIDO1,APELLIDO2) FROM tabla;

Primer problema, lo más normal es que la gente meta un espacio ya sea porque se le escape o porque al importarlo lo ha cogido asi que hacemos un concat pero esta vez eliminando los espacios

SELECT REPLACE(CONCAT(NOMBRE,APELLIDO1,APELLIDO2) ), ' ', '') FROM tabla;

Pero claro, si uno de los campos está a null falla fijo así que lo que hacemos es comprobar antes de concatenar si el campo está a null para sustituirlo por un espacio

SELECT REPLACE(CONCAT(COALESCE(NOMBRE,''), COALESCE(APELLIDO1,''), COALESCE(APELLIDO2,'')) ), ' ', '') FROM tabla;

Todo esto claro está, teniendo en cuenta que la base de datos está configurada para que no distinga acentos ni mayúsculas porque si no ya toca rizar el rizo:

SELECT UPPER(REPLACE(CONCAT(COALESCE(NOMBRE,''), COALESCE(APELLIDO1,''), COALESCE(APELLIDO2,'')) ), ' ', '')) FROM tabla COLLATE utf8_bin;

Importar un CSV a MySQL tratando los campos

Estos días ando pegándome con una aplicación para importar datos directamente desde ficheros CSV sin importar la estructura que estos tengan. La verdad bastante divertido sobretodo porque toca pegarme con cosas que habitualmente no se hacen. Como por ejemplo usar la función fgetcsv de php que parsea el csv y te lo guarda en una estructura, muy útil la verdad. Por ejemplo la función que uso en la clase de importación para coger el fichero y cargarlo sería de la siguiente forma:

/* La función recoge dos parámetros, el nombre del fichero ya subido al servidor y el tipo de importación (en esta aplicación dependiendo del tipo de importación trata los datos de una forma o de otra) */
public function cargar($fichero, $tipo){
        $columnas = array();
        $this->tabla = "tmp_".$tipo."_".$fichero;
  // abrimos el fichero y lo recorremos para saber los nombres de las columnas
        $fpointer = fopen($this->path.'/archivos/importaciones/'.$fichero.'.csv', "r");
    
        if ($fpointer){
            $_separador = ';';
            $arr = fgetcsv($fpointer, 10*1024, $_separador);
            if(count($arr) == 1){
                fclose($fpointer);
                $fpointer = fopen($this->path.'/archivos/importaciones/'.$fichero.'.csv', "r");
                $_separador = ',';
                $arr = fgetcsv($fpointer, 10*1024, $_separador);
            }
            
            if(is_array($arr) && !empty($arr)){
                    foreach($arr as $val){
                        if(trim($val)!="") $columnas[] = $val;
                    }    
            }            
            unset($arr);
           // una vez tenemos los nombres de las columnas creamos una nueva table con todas las columnas del csv            
            $sql = "CREATE TABLE IF NOT EXISTS tmp_".$tipo."_".$fichero." (`id` int(11) NOT NULL AUTO_INCREMENT, `ib_tramitado` char(1) DEFAULT 'N',";
            if(!empty($columnas)){
              $arr = array();
              for($i=0; $i<sizeof($columnas); $i++){
                  $arr&#91;&#93; = "`".$columnas&#91;$i&#93;."` TEXT";
              }    
              $sql .= implode(",", $arr);
              $sql .= ", PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
              // ejecutamos la consulta con mi clase de base de datos, pero se podría usar cualquiera que ejecute la query almacenada en la variable $query
              db::query($sql);
              // recoremos de nuevo el fichero pero ya insertando los datos en la tabla que hemos creado
              while(! feof($fpointer)){
                  $_registro = array();
                  $_valores = fgetcsv($fpointer, 10*1024, $_separador);
                  foreach($columnas as $indice=>$columna){
                      if(isset($_valores[$indice])){
                          $_registro["`". $columna ."`"]=$_valores[$indice];
                      }
                  }
// lo mismo, estoy usando mi clase de acceso a base de datos pero se podría usar cluarquier otra
                  db::insert("tmp_".$tipo."_".$fichero, $_registro);                  
              }              
            }
      } 
      fclose($fpointer); 
      foreach($columnas as $columna){
          $this->columnas[] = "`". $columna ."`";
      }
// devolvemos la estructura con las columnas que tiene la tabla
      return $this->columnas;
    }

Todos los campos se han importado a la tabla temporal como tipo TEXT porque no sabemos el tipo de dato que van a tener. Si sabemos que alguno de los datos es un número, podemos “limpiarlo” de símbolos raros con un simple update. En mi caso era un campo de moneda que habían dejado con el símbolo del euro y los puntos como separadores de millares.

update $tabla set $campo = CONVERT(replace($campo, '.', ''),UNSIGNED INTEGER)

Y luego ya “solo” toca tratar los datos pero eso ya depende de la estructura de base de datos.