Salut,
Nouvel article dans la rubrique Perl à propos de Perl et les bases de données.
Vos commentaires, corrections et remarques sont les bienvenus.
N.B. : il en sera de même pour les nouveaux articles de notre rubrique.
Merci
Salut,
Nouvel article dans la rubrique Perl à propos de Perl et les bases de données.
Vos commentaires, corrections et remarques sont les bienvenus.
N.B. : il en sera de même pour les nouveaux articles de notre rubrique.
Merci
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
Pour ceux qui travaillent sous Oracle, cet article est il suffisant pour vous ?
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
Je pense que la partie sur les placeholder devrait mentionner lourdement le fait qu'utiliser des placeholders protège efficacement contre l'injection SQL, ce fléau des sites webs dynamiques... Comme DBI est souvent utilisé dans un contexte web ça me semble pratiquement plus important que l'aspect optimisation.
--
Jedaï
Ok jedai.
Je vais le préciser. N'hésite pas si tu as d'autres remarques.
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
Tout d'abord, un très grand merci à l'équipe PERL et à Djibril en particulier.
Le PERL est le langage avec lequel j'ai pu démarrer le plus rapidement (et même plus vite que PHP), et ce, en partie grâce à la FAQ et aux tutos très bien fournis de dvp.com.
Je voulais juste ajouter un petit commentaire:
Pour le débutant Perl qui a déjà passé pas mal de temps sur les aspects mysql dans d'autres langages, il n'est pas évident de se lancer dans un script fonctionnel.
D'où la suggestion:
Serait-il possible d'ajouter un petit chapitre du genre "exemple complet SELECT, INSERT, UPDATE..." avec toutes les techniques appropriées (requetes préparées, placeholders etc..) ?
Pour donner une idée du besoin, si toutefois c'était nécessaire, je peux montrer le genre de script qui m'a pris un temps fou, avec un résultat médiocre car je n'ai pas le temps de patauger dans les docs pour réaliser un sed ou un "preg_replace".
Bon voila : la suggestion serait de reprendre un cdc similaire pour expliquer perl:dbi en utilisation, disons, plus avancée :
- options d'execution du script avec un mode "debug",
- choix du mode "insert" ou "update"
- conditions sql "multiples",
- controle des entrées, par ex comparer avec les champs de la db pour ne pas chercher à mettre un jour un champ AI,
- requetes préparées avec placeholders .. avec des tableaux,
- contrôle du résultat (affectedrows ou équivalent ...)
- log des sorties
Pour ne pas faire celui qui réclame un script tout fait, voilà une base pour illustrer mon idée (c'est uniquement pour l'idée d'un cdc qui je crois peut être assez commun, je répète, le script est ... hum... j'ai honte, mais bon ça montre aussi les erreurs et problématiques du noob que je suis) :
Voila pour l'idée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 #!/usr/bin/perl -w # ################################################################################################# # What: insert or update into db # Created: 05/12/2010 # Modified: void # ################################################################################################# # ################################################################## # USAGE examples # INSERT # ./my_db_insert.pl --debug --database foo --table bar --user apache_user --pwd ze_mega_pwd --fields "id, id_client, serial_number, status, status_date" --datas "DEFAULT,109,123456,1," # UPDATE (AI fields to be removed, condition(s) to be added) # ./my_db_insert.pl --debug --database foo --table bar --user apache_user --pwd ze_mega_pwd --fields "id_client, serial_number, status, status_date" --datas "109,1234568,1," --condition1 "id_client:109" --condition2 "serial_number:1234567" # ################################################################## # ------------------------------------------------------------------ # TODO # Check that there is NO primary AI key in the fields when UPDATE # Update conditions shall be free (not fixed to 2 conditions only) # Generate LOGS # ------------------------------------------------------------------ # # MODULES # use strict; use Switch; use DBI; use DBD::mysql; use Getopt::Long (); use Term::ANSIColor; # # CONSTANT # use constant true => 1; use constant TRUE => 1; use constant false => 0; use constant FALSE => 0; use constant DEBUG => true; # # SUB # sub usage { my $message = $_[0]; if (defined $message && length $message) { $message .= "\n" unless $message =~ /\n$/; } my $command = $0; $command =~ s#^.*/##; print STDERR ( $message, "usage: $command --debug --database db_name --table table --user db_user --pwd db_pwd --fields insert_fields --datas insert_data --condition insert_condition\n" ); die("\n") } sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } sub create_placeholder{ # fields as an array passed to the function my(@args) = @_; my $string = $args[0]; my @binded = split(/,/, $string); foreach (@binded) { s/^.*$/\?/g; } # transform array to string $string = join("," , @binded ); return $string; } # # DEFAULT PARAMETERS # my $db_name; my $table; my $db_user; my $db_pwd; my $fields; my $datas; my $sql_condition; my $condition1; my $condition2; my $first_cond_field; my $first_cond_data; my $second_cond_field; my $second_cond_data; my $query; my $host = 'localhost'; my $debug; my @datas_array; # my $affectedrows; # # USER INPUT PARAMETERS # Getopt::Long::GetOptions( 'debug' => sub { $debug = DEBUG; print "DEBUG mode active\n" if ($debug); }, 'db|database=s' => \$db_name, 't|table=s' => \$table, 'u|user=s' => \$db_user, 'p|pwd=s' => \$db_pwd, 'f|field|fields=s' => \$fields, 'd|data|datas=s' => \$datas, 'c1|condition1=s' => sub { local *_ = \$_[1]; # /^([^:]+):(\w+)$/ /^([^:]+):([^:]+)$/ or die("Invalid format for option s.\n"); # secure a bit datas (sql injection by WHERE A=A clause) $first_cond_field = &trim($1); $first_cond_data = &trim($2); if ($first_cond_data eq $first_cond_field) { $condition1 = ""; } else{ $condition1 = TRUE; } }, 'c2|condition2=s' => sub { local *_ = \$_[1]; # /^([^:]+):(\w+)$/ /^([^:]+):([^:]+)$/ or die("Invalid format for option s.\n"); # secure a bit datas (sql injection by WHERE A=A clause) $second_cond_field = &trim($1); $second_cond_data = &trim($2); if ($second_cond_data eq $second_cond_field) { $condition2 = ""; } else{ $condition2 = TRUE; } }, ) or usage("Invalid command line options."); if (!defined $debug) { $debug = false; } usage("The database must be specified.") unless defined $db_name; usage("The database table must be specified.") unless defined $table; usage("The database user must be specified.") unless defined $db_user; if (!defined $db_pwd) { print "The database user pwd MUST be specified,\n pls enter the db user pwd now: "; $db_pwd = <STDIN>; chomp($db_pwd); # remove EOL } usage("The database insert fields must be specified.") unless defined $fields; usage("The database insert values must be specified.") unless defined $datas; if (!defined $condition1 || length($condition1) == 0 ) { print color ('bold blue'), "#" x 60, "\nInfo : no sql condition has been specified (=> INSERT mode)\n", "#" x 60, "\n", color("reset"); $condition1 = ""; $condition2 = ""; # we assume that if only 1 condition is specified => it goes to $condition1 $sql_condition = ""; } else{ print color ('bold blue'), "#" x 60, "\nInfo : sql condition has been specified (=> UPDATE mode)\n", "#" x 60, "\n", color("reset"); $condition1 = "$first_cond_field = $first_cond_data" ; $condition2 = (defined $second_cond_data || length($second_cond_data) != 0 ) ?" AND $second_cond_field = $second_cond_data" : ""; $sql_condition = $condition1 . $condition2 ; } # # DEBUG CONTROL # print "\n", "#" x 60, "\nINPUT PARAMETERS CONTROL\n" if ($debug) ; print "DEBUG: $debug,\ndatabase: $db_name,\ntable: $table,\nuser: $db_user,\npwd:$db_pwd,\nInsert fields:$fields,\nInsert datas: $datas,\ncondition: $sql_condition\nhost:$host\n" if ($debug) ; print "#" x 60, "\n"; # # DB CONNECTION # # # Connect to dB # my $dbd = DBI->connect("dbi:mysql:dbname=$db_name;host=$host;mysql_server_prepare=1;",$db_user, $db_pwd) or die 'Connexion impossible à la base de données : '.DBI::errstr; # # Query : insert or update # # INSERT if ( !$sql_condition || !defined $sql_condition || length(&trim($sql_condition)) == 0 ) { # FLAG my $flag="insert_mode"; print "mode: $flag\n" if ($debug); # DATAS: Create a placeholder string my $place_holder = &create_placeholder($fields); print "Place holder: $place_holder\n" if ($debug); # if no binded params: $query = "INSERT INTO $table ($fields) VALUES ($datas)"; $query = "INSERT INTO $table ($fields) VALUES ($place_holder)"; print $query,"\n" if ($debug); print "datas: $datas\n" if ($debug); @datas_array = split(",", $datas); print "datas array:" , @datas_array , "\n" if ($debug); } # UPDATE else { # FLAG my $flag="update_mode"; print "mode: $flag\n" if ($debug); # build bind_params : field_1 = ?, ... , field_n = ? my @field_array = split("," , $fields) ; foreach (@field_array) { s/^(.*)$/$1=?,/g; } # remove trailing "," @field_array->[-1] =~ s/^(.*),+$/$1/g ; print "field_array: @field_array\n" if ($debug); # update query # $query = "UPDATE $table SET $fields=$datas WHERE $sql_condition"; $query = "UPDATE $table SET @field_array WHERE $sql_condition"; print $query,"\n" if ($debug); @datas_array = split(",", $datas); print "datas array:" , @datas_array , "\n" if ($debug); } # # Prepare # my $prepared = $dbd->prepare($query) or die 'Parse de la table: Impossible de préparer la requête : '.$dbd->errstr; # # Bind Params # my $inc=0; foreach (@datas_array) { $prepared->bind_param($inc+1, $datas_array[$inc]); # nota: placeholders are numbered from 1 $inc++; } # # Execute queries # $prepared->execute() or die 'Parse de la table: Impossible d\'exécuter la requête : '.$prepared->errstr; # Not binded : # my $result = $prepared->execute( $datas ) # or die 'Parse de la table: Impossible d\'exécuter la requête : '.$prepared->errstr; # # Check result # # AFFECTED ROWS (method not available with "DBD::mysql" module but with "use::Mysql") # $affectedrows = $result->affectedrows($query); # print "Result : $affectedrows affected rows","\n" if ($debug); # # Free memory and disconnect dB # $prepared->finish; $dbd->disconnect;
Article mis à jour !
Bonne lecture.
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
Bonjour djibril,
Avant tout un grand MERCI pour ce superbe tuto
Une seule petite anomalie le lien télécharger les fichiers est mort.
Pour le reste c'est sous toute réserve vu que je suis resté 10 ans sans toucher à Oracle (depuis la 8i), donc comme d'hab c'est pour passer le temps...
Ceci dit je ne suis pas trop dépaysé
Pour toutes les bases :
Dans le fichiers des communes de 2013, le champ AR (Arrondissement) n'est pas renseigné, seulement sur les 17 dernières lignes.
Pour rester cohérent avec le NOT NULL je l'ai renseigné par un zéro, non utilisé pour toutes les autres communes.
Pour Oracle quelques modifs mineures :
* Pour la création :
- Connexion à BDD
- Lecture des fichiers avec '<:encoding(UTF-8)' sinon on a pas les accents dans la base
- Requetes de création sous forme de fichier.sql pour centraliser les créations, çà c'est une préférence perso
- Modification table COMMUNES car Oracle ne gère pas les colonnes AUTO_INCREMENT Remplacement par une SEQUENCE et un TRIGGER
* Pour l'interrogation :
- Connexion à BDD
- Oracle renvoie les noms des colonnes en MAJUSCULES ce qui implique dans les selectrow_hashref par ex :
$ref_commune->{'NBRCOMMUNES'} au lieu de $ref_commune->NbrCommunes}
Ainsi que dans les clauses AS SELECT COUNT( id_communes ) as NBRCOMMUNES
- Modif des clauses LIKE avec ? pour méthode $sth->bind_columns
Donc rien de très différent ! PS :
- Je n'avais pas perçu de suite le pb des colonnes en MAJUSCULE j'étais donc parti sur bind_columns... je l'ai laissé dans le script, ça fait un exemple...
- J'ai supprimé les clauses JOIN dans le requêtes, selon mes habitudes de vieux
Le plus simple je joins le répertoire zippé qui contient tout, avec des commentaires plus précis.
Si ce n'est pas clair n'hésite pas...
Encore MERCI![]()
Merci dmganges, le lien de téléchargement a été corrigé.
Je lis le reste et te tiens au courant.
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
L'article a été mis à jour :
- données INSEE mises à jour ;
- nouveaux exemples de code pour une base de données Oracle (merci dmganges) ;
- codes mises à jour pour une meilleure gestion des accents ;
- ...
N'hésitez pas à laisser vos commentaires.
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
MERCI à toi djibril,
En local je ne m'étais pas préoccupé du host (implicite)
La connexion plus complète est :
PrintError => 0 n'est là que pour éviter d'avoir les erreurs "printées" 2 fois la première par Oracle la deuxième par or die.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #!/usr/bin/perl use warnings; use strict; use utf8; use DBI; # Charge le module DBI my $host = "localhost"; my $port = "1521"; my $bdd = "XE"; my $user = "michel"; my $pass = "michel"; my $dbh = DBI->connect( "dbi:Oracle:host=$host;port=$port;sid=$bdd", $user, $pass, { PrintError => 0, AutoCommit => 0 }) or die "\nERR=Connexion impossible à la base de données $bdd\n $! \n $@\n$DBI::errstr"; my ($Sysdate) = $dbh->selectrow_array("SELECT sysdate FROM dual") or die "\nERR=Sysdate\n $! \n $@\n$DBI::errstr"; print "Base OK Date = $Sysdate\n\n";
AutoCommit => 1 On laisse Oracle faire ses commit comme il l'entend, mais en cas de pb un rollback explicite n'est pas pris en compte !
AutoCommit => 0 un rollback est possible mais doit être explicite, sinon en fin de traitement sans erreur un commit implicite est réalisé.
AutoCommit => 0 est préférable, surtout si on a l'habitude de faire un copier/coller de la connexion...
Merci, l'article a été mis à jour.
- Les meilleurs cours et tutoriels Perl et Perl 6 pour vous former ;
- FAQ Perl, Perl 6 et Perl/Tk d'entraide ;
- Les news sur la rubrique Perl ;
- S'abonner au compte Twitter de la rubrique Perl ;
- Mes tutoriels developpez.com.
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager