Finalmente ho fatto il mio primo giro del nuovo anno con la mia amata drosera.
81 chilometri da Bologna passando per Calderino, Badia , Savigno, l’abbazia di Monteveglio, Stiore, Monte San Pietro e ritorno.
Peccato gli ultimi 20 chilometri abbia piovuto, ma ai fini del giro è stato irrilevante.
Troppo bello.
Un paio di scatti col cellulare. Fanno veramente schifo come taglio, ma almeno non sono venuti pessimi.
A Savigno.
Sotto l’abbazia di Monteveglio:
Il tragitto.
Oggi nel canale perl ci si è chiesto come individuare stringhe arbitrarie ricorrenti in un file (ie: query SQL in un file php).
La risposta di per se sarebbe semplice: si fa una regex che inizia con SELECT e finisce con qualcosa (ie:
e si è a cavallo.
Il grado di difficoltà però aumenta se le stringhe sono su più righe…
Avendo trovato una soluzione che non richiede nemmeno un ciclo, la scrivo poichè ne sono orgoglioso e mi è valsa un ++.
use strict;
use File::Slurp;
my $text = read_file(‘file.php’);
my @queries = $text =~ /("SELECT.*?");/msg
Ogni valore di @queries conterrà uno dei SELECT nel file, siano essi su più righe o meno.
Più breve di così…
Segnalo anche un paio di letture sulle regex che potrebbero venire comode per capire i modificatori /m e /s, che si usano pochino.
Regexp Power by Simon Cozens (1 e 2)
acronimo: dal greco akron (estremo) + onoma (nome). Indica una sigla composta dalle iniziali di piùparole.
Qua c’è da uscire di senno. A me MySQL sta pure simpatico, ma fa veramente di tutto per farmi sentire male.
Parto proprio dall’inizio.
sim:none> CREATE DATABASE test CHARACTER SET = 'UTF8'; Query OK, 1 row affected (0.00 sec) sim:none> CONNECT test; Connection id: 230 Current database: test
Ammettiamo che io voglia creare una tabella canonica con vari campi, fra cui l’id come PK, un campo per segnare quando il record è stato creato (created) ed uno per segnarmi quando è stato aggiornato l’ultima volta (updated).
sim:test> CREATE TABLE A (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
word VARCHAR(8) NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated TIMESTAMP NOT NULL );
Query OK, 0 rows affected (0.00 sec)
La situazione della mia tabella A per ora è chiara.
sim:test> SHOW CREATE TABLE A \G;
*************************** 1. row ***************************
Table: A
Create Table: CREATE TABLE `A` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`word` varchar(8) NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
Inserisco anche un paio di record che appaiono come ci si aspetta:
sim:test> INSERT INTO A (word) VALUES ('pippo'),('pluto');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
sim:test> SELECT * FROM A;
+----+-------+---------------------+---------------------+
| id | word | created | updated |
+----+-------+---------------------+---------------------+
| 1 | pippo | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
| 2 | pluto | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
+----+-------+---------------------+---------------------+
2 rows in set (0.00 sec)
Nel caso si decida di aggiornare un record:
sim:test> UPDATE A SET word = 'topolino' WHERE id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 sim:test> SELECT * FROM A; +----+----------+---------------------+---------------------+ | id | word | created | updated | +----+----------+---------------------+---------------------+ | 1 | pippo | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 | | 2 | topolino | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 | +----+----------+---------------------+---------------------+ 2 rows in set (0.00 sec)
A questo punto decido che questa disposizione dei dati non mi va più bene, che fare? Semplice (* le ultime parole famose TM ), leggo il manuale e sistemo. Seee…
Un po’ di pazzia MySQL:
sim:test> SHOW COLUMNS FROM A; +---------+------------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------------------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | word | varchar(8) | NO | | NULL | | | created | timestamp | NO | | CURRENT_TIMESTAMP | | | updated | timestamp | NO | | 0000-00-00 00:00:00 | | +---------+------------------+------+-----+---------------------+----------------+ 4 rows in set (0.00 sec) sim:test> ALTER TABLE A ALTER created DROP DEFAULT; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 sim:test> SHOW COLUMNS FROM A; +---------+------------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------------------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | word | varchar(8) | NO | | NULL | | | created | timestamp | NO | | NULL | | | updated | timestamp | NO | | 0000-00-00 00:00:00 | | +---------+------------------+------+-----+---------------------+----------------+ 4 rows in set (0.00 sec) sim:test> ALTER TABLE A CHANGE created creat TIMESTAMP; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 sim:test> SHOW COLUMNS FROM A; +---------+------------------+------+-----+---------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------------------+-----------------------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | word | varchar(8) | NO | | NULL | | | creat | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | | updated | timestamp | NO | | 0000-00-00 00:00:00 | | +---------+------------------+------+-----+---------------------+-----------------------------+ 4 rows in set (0.00 sec)
Con un magico DROP del DEFAULT di un campo ed un cambio nome ottengo di nuovo il CURRENT_TIMESTAMP come default, e pure l’update automatico sul campo.
Provare per credere:
sim:test> INSERT INTO A (word) VALUES ('minnie');
Query OK, 1 row affected (0.00 sec)
sim:test> SELECT * FROM A;
+----+----------+---------------------+---------------------+
| id | word | creat | updated |
+----+----------+---------------------+---------------------+
| 1 | pippo | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
| 2 | topolino | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
| 3 | minnie | 2010-02-11 23:02:36 | 0000-00-00 00:00:00 |
+----+----------+---------------------+---------------------+
3 rows in set (0.00 sec)
sim:test> UPDATE A SET word = 'clarabella' WHERE id=3;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 1
sim:test> SELECT * FROM A;
+----+----------+---------------------+---------------------+
| id | word | creat | updated |
+----+----------+---------------------+---------------------+
| 1 | pippo | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
| 2 | topolino | 2010-02-11 22:23:41 | 0000-00-00 00:00:00 |
| 3 | clarabel | 2010-02-11 23:03:35 | 0000-00-00 00:00:00 |
+----+----------+---------------------+---------------------+
3 rows in set (0.00 sec)
Robe da pazzi.
Note:
1) MySQL aggiunge alle funzionalità dell’SQL (che vorrebbe una sola query per riga) la possibilità di comandi multipli in un solo statement: ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
Ufff. E’ ora di pensionare un centinaio di VHS che non ha senso tenere lì ad occupare spazio inutilmente.
C’è roba a cui sono veramente affezionato, e che mi ha seguito per più di ventanni attraverso innumerevoli traslochi e riordini.
Excalibur, la mia prima VHS. Poi Braveheart, Star Wars, il Lago dei Cigni, il Flauto Magico, Kenshiro il film, Macross e la collezione completa di Robotech (oltre 40 videocassette). Ghost in the Shell… un sacco di roba.
E non ho ovviamente ricomprato tutti i DVD… ammesso pure che si trovi.
Sic sic.
Dovevo trasferire rapidamente i dati da una singola tabella in un db MySQL a quattro distinte – in modo da normalizzare un po’ i dati.
Con perl e DBI la cosa viene facile.
use strict;
use DBI;
[…]
my $dsn = "dbi:mysql:database=$db_name";
my $dbh = DBI->connect( $dsn, $username, $password ) or die $DBI::errstr;
my $sth = $dbh->prepare(
‘SELECT name, surname, birth, address, cap, city, country, phone, email, notes FROM rubrica’
) or die $dbh->errstr;
$sth->execute();
my $ins0 = $dbh->prepare(
‘INSERT INTO persone (nome,cognome) VALUES (?,?)’
) or die $dbh->errstr;
my $ins1 = $dbh->prepare(
‘INSERT INTO indirizzi (id,via,cap,citta,paese) VALUES (?,?,?,?,?)’
) or die $dbh->errstr;
[… ecc, seguono altri statement insert …]
while ( my $row = $sth->fetchrow_hashref() ) {
$ins0->execute( $row->{name}, $row->{surname} );
my $rv = $dbh->last_insert_id(undef, undef, ‘persone’, ‘id’);
$ins1->execute( $rv, $row->{address}, $row->{cap}, $row->{city}, $row->{country} );
[…]
}
La cosa interessante sta in quel last_insert_id che raccatta l’ultimo valore auto incrementato e lo mette in uno scalare, riutilizzabile poi in altri insert per avere le foreign key allineate.



