Mysql
 sql >> Database >  >> RDS >> Mysql

Dividere una stringa e scorrere i valori in MySql Procedure

Dovrai essere un po' più attento con la manipolazione delle stringhe. Non puoi usare REPLACE() per questo, perché sostituirà più occorrenze, danneggiando i tuoi dati se un elemento nell'elenco separato da virgole è una sottostringa di un altro elemento. Il INSERT() funzione di stringa è meglio per questo, da non confondere con il INSERT istruzione utilizzata per l'inserimento in una tabella.

DELIMITER $$

DROP PROCEDURE IF EXISTS `insert_csv` $$
CREATE PROCEDURE `insert_csv`(_list MEDIUMTEXT)
BEGIN

DECLARE _next TEXT DEFAULT NULL;
DECLARE _nextlen INT DEFAULT NULL;
DECLARE _value TEXT DEFAULT NULL;

iterator:
LOOP
  -- exit the loop if the list seems empty or was null;
  -- this extra caution is necessary to avoid an endless loop in the proc.
  IF CHAR_LENGTH(TRIM(_list)) = 0 OR _list IS NULL THEN
    LEAVE iterator;
  END IF;
 
  -- capture the next value from the list
  SET _next = SUBSTRING_INDEX(_list,',',1);

  -- save the length of the captured value; we will need to remove this
  -- many characters + 1 from the beginning of the string 
  -- before the next iteration
  SET _nextlen = CHAR_LENGTH(_next);

  -- trim the value of leading and trailing spaces, in case of sloppy CSV strings
  SET _value = TRIM(_next);

  -- insert the extracted value into the target table
  INSERT INTO t1 (c1) VALUES (_value);

  -- rewrite the original string using the `INSERT()` string function,
  -- args are original string, start position, how many characters to remove, 
  -- and what to "insert" in their place (in this case, we "insert"
  -- an empty string, which removes _nextlen + 1 characters)
  SET _list = INSERT(_list,1,_nextlen + 1,'');
END LOOP;

END $$

DELIMITER ;

Successivamente, una tabella per il test:

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c1` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

La nuova tabella è vuota.

mysql> SELECT * FROM t1;
Empty set (0.00 sec)

Chiama la procedura.

mysql> CALL insert_csv('foo,bar,buzz,fizz');
Query OK, 1 row affected (0.00 sec)

Nota che "1 riga interessata" non significa cosa ti aspetteresti. Si riferisce all'ultimo inserto che abbiamo fatto. Poiché inseriamo una riga alla volta, se la procedura inserisce almeno una riga, otterrai sempre un conteggio delle righe pari a 1; se la procedura non inserisce nulla, otterrai 0 righe interessate.

Ha funzionato?

mysql> SELECT * FROM t1;
+----+------+
| id | c1   |
+----+------+
|  1 | foo  |
|  2 | bar  |
|  3 | buzz |
|  4 | fizz |
+----+------+
4 rows in set (0.00 sec)