store_data_safely:an_intro_to_sqlite
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
store_data_safely:an_intro_to_sqlite [2013/09/30 21:36] – [9] fredphil91 | store_data_safely:an_intro_to_sqlite [2013/10/20 12:16] (Version actuelle) – andre_domenech | ||
---|---|---|---|
Ligne 25: | Ligne 25: | ||
Avec notre base de données relationnelle, | Avec notre base de données relationnelle, | ||
- | • des structures de données complexes | + | • des structures de données complexes |
- | • la facilité d' | + | • la facilité d' |
- | • un accès simple à partir de n' | + | • un accès simple à partir de n' |
- | • des instructions de base de données dans une langue proche de l' | + | • des instructions de base de données dans une langue proche de l' |
• l' | • l' | ||
- | Heureusement (pour nous), la base de données relationnelle a été inventé | + | Heureusement (pour nous), la base de données relationnelle a été inventée |
Un exemple d' | Un exemple d' | ||
Ligne 47: | Ligne 47: | ||
Hopefully, you use Firefox as your browser, as you need to install an extension (SQLite Manager 0.7.7) in order to load a full GUI interface which will allow for prompting, execution and testing of your SQL. Once you like what you see, you can transfer the SQL statements to your favourite programming language, which could be anything from BASH to BASIC.** | Hopefully, you use Firefox as your browser, as you need to install an extension (SQLite Manager 0.7.7) in order to load a full GUI interface which will allow for prompting, execution and testing of your SQL. Once you like what you see, you can transfer the SQL statements to your favourite programming language, which could be anything from BASH to BASIC.** | ||
- | Une commande SQL commence par un verbe, éventuellement suivi de plusieurs qualificatifs, | + | Une commande SQL commence par un verbe, éventuellement suivi de plusieurs qualificatifs, |
Outre l' | Outre l' | ||
Ligne 71: | Ligne 71: | ||
Pour ajouter la bonne extension pour Firefox : | Pour ajouter la bonne extension pour Firefox : | ||
- | • dans Firefox, cliquez sur le menu Outils > Modules complémentaires | + | • dans Firefox, cliquez sur le menu Outils > Modules complémentaires |
- | • dans la boîte de recherche, saisissez SQLite Manager, vous devriez voir une entrée | + | • dans la boîte de recherche, saisissez SQLite Manager, vous devriez voir une entrée |
• cliquez dessus et vous devriez voir une boîte de dialogue vous demandant de confirmer votre décision. | • cliquez dessus et vous devriez voir une boîte de dialogue vous demandant de confirmer votre décision. | ||
Vous devrez alors redémarrer Firefox pour que cela prenne effet. | Vous devrez alors redémarrer Firefox pour que cela prenne effet. | ||
- | Nous sommes maintenant prêts à démarrer | + | Nous sommes maintenant prêts à démarrer, mais nous devrions faire un peu de conception de base de données avant de plonger. |
- | Une base de données SQL a une structure très simple : elle consiste en un certain nombre de table qui ressemblent beaucoup à des feuilles de calcul ; elles ont un nombre prédéfini de colonnes (défini lors de la création de la table), et un nombre illimité de lignes. | + | Une base de données SQL a une structure très simple : elle consiste en un certain nombre de tables |
- | Il n'y a effectivement | + | Il n'y a effectivement |
====== 5 ====== | ====== 5 ====== | ||
Ligne 95: | Ligne 95: | ||
I've tried to follow a simple naming convention: | I've tried to follow a simple naming convention: | ||
- | Cela soulève probablement la question de la performance lorsqu' | + | Cela soulève probablement la question de la performance lorsqu' |
- | Il est important de souligner qu'une base de données SQLite est stockée comme un seul grand fichier | + | Il est important de souligner qu'une base de données SQLite est stockée comme un seul grand fichier, ce qui rend, concernant |
L' | L' | ||
Ligne 120: | Ligne 120: | ||
Nous allons créer quatre tables : | Nous allons créer quatre tables : | ||
- | Tetudiant (une ligne par élève) | + | Tetudiant (une ligne par élève). |
- | Tadresse (une ligne par ligne d' | + | Tadresse (une ligne par ligne d' |
- | Tnom_examen (une ligne pour chaque série d' | + | Tnom_examen (une ligne pour chaque série d' |
- | Texamens (une ligne par étudiant et par examen passé) | + | Texamens (une ligne par étudiant et par examen passé). |
- | Notez que nous aurions pu stocker l' | + | Notez que nous aurions pu stocker l' |
Ce processus par lequel un champ extensible est déplacé dans une table secondaire est un exemple de « normalisation » et est une caractéristique importante de la conception de base de données. | Ce processus par lequel un champ extensible est déplacé dans une table secondaire est un exemple de « normalisation » et est une caractéristique importante de la conception de base de données. | ||
Ligne 143: | Ligne 143: | ||
So it's now time to create our first table. In practice, it's a good idea to set out your tables on paper before entering them into the computer as there is rarely an absolutely “correct” way to design these things.** | So it's now time to create our first table. In practice, it's a good idea to set out your tables on paper before entering them into the computer as there is rarely an absolutely “correct” way to design these things.** | ||
- | Tout d' | + | Tout d' |
- | Vous verrez alors un écran plutôt clairsemé ; choisissez Base de données dans le menu et cliquez sur Nouvelle base de données:- | + | Vous verrez alors un écran plutôt clairsemé ; choisissez Base de données dans le menu et cliquez sur Nouvelle base de données : - Nous allons appeler notre base de données « Examen », saisissez Examen dans la boîte de dialogue — le système ajoutera .sqlite à la fin et vous demandera de choisir un dossier pour la mettre — je vous suggère de choisir votre répertoire personnel. |
- | Nous allons appeler notre base de données « Examen », saisissez Examen dans la boîte de dialogue — le système ajoutera .sqlite à la fin et vous demandera de choisir un dossier pour la mettre — je vous suggère de choisir votre répertoire personnel. | + | |
Cela nous donne un écran initial d' | Cela nous donne un écran initial d' | ||
Ligne 166: | Ligne 165: | ||
So now we have a properly formatted table, but it still has to be filled with data.** | So now we have a properly formatted table, but it still has to be filled with data.** | ||
- | Tetudiant aura quatre colonnes (celles-ci sont parfois | + | Tetudiant aura quatre colonnes (celles-ci sont parfois |
- | Cette liste montre les principales opérations que nous pouvons faire sur les tables | + | Cette liste montre les principales opérations que nous pouvons faire sur les tables (Drop signifie supprimer une table en langage SQL). |
Nous voulons créer une table ; faisons-le grâce au formulaire qui sert à définir notre table (ci-dessus). | Nous voulons créer une table ; faisons-le grâce au formulaire qui sert à définir notre table (ci-dessus). | ||
- | SQLite est différent des autres bases de données SQL en ce sens qu'il n'y a que quelques classes de données différentes (entier, réel, texte, null, BLOB); aucune taille n' | + | SQLite est différent des autres bases de données SQL en ce sens qu'il n'y a que quelques classes de données différentes (entier, réel, texte, null, BLOB) ; aucune taille n' |
- | Il faut confirmer que nous voulons vraiment créer cette table — et on voit l' | + | Il faut confirmer que nous voulons vraiment créer cette table, et on voit l' |
Maintenant, nous avons donc un tableau bien formaté, mais il doit encore être rempli de données. | Maintenant, nous avons donc un tableau bien formaté, mais il doit encore être rempli de données. | ||
Ligne 189: | Ligne 188: | ||
id_etudiant mérite quelques explications ; nous l' | id_etudiant mérite quelques explications ; nous l' | ||
- | Les clés primaires peuvent être constituées de plus d'une colonne | + | Les clés primaires peuvent être constituées de plus d'une colonne |
C'est habituel, mais pas obligatoire, | C'est habituel, mais pas obligatoire, | ||
- | Bien que nous ayons mentionné les clés primaires, ce ne sont pas les seuls types de clé à considérer. Il convient de mentionner qu'il existe des « clés étrangères » et nous donnerons un exemple de leur utilité plus tard. | + | Bien que nous ayons mentionné les clés primaires, ce ne sont pas les seuls types de clés à considérer. Il convient de mentionner qu'il existe des « clés étrangères » et nous donnerons un exemple de leur utilité plus tard. |
====== 10 ====== | ====== 10 ====== | ||
Ligne 204: | Ligne 203: | ||
However, entering data one line at a time will lead to very poor database performance. Because we didn't specify how many SQL statements form a logical transaction unit, SQLite assumes the single | However, entering data one line at a time will lead to very poor database performance. Because we didn't specify how many SQL statements form a logical transaction unit, SQLite assumes the single | ||
- | Nous pouvons maintenant inscrire des étudiants (un à la fois). Le collège a décidé que l' | + | Nous pouvons maintenant inscrire des étudiants (un à la fois). Le collège a décidé que l' |
Sélectionnez la table Tetudiant et choisissez l' | Sélectionnez la table Tetudiant et choisissez l' | ||
Ligne 210: | Ligne 209: | ||
Après avoir entré vos données, le système vous montrera l' | Après avoir entré vos données, le système vous montrera l' | ||
- | Toutefois, saisir des données ligne par ligne mènera à de très mauvaises performances de la base de données. Comme nous n' | + | Toutefois, saisir des données ligne par ligne mènera à de très mauvaises performances de la base de données. Comme nous n' |
====== 11 ====== | ====== 11 ====== | ||
Ligne 225: | Ligne 224: | ||
We can enter any reasonable number of statements (thousands) that make sense—covering multiple tables and various operations. When we reach the COMMIT statement, the database can be considered to have been properly updated. Alternatively, | We can enter any reasonable number of statements (thousands) that make sense—covering multiple tables and various operations. When we reach the COMMIT statement, the database can be considered to have been properly updated. Alternatively, | ||
+ | La solution consiste à effectuer un certain nombre de mises à jour de base de données comme une seule transaction logique. Nous faisons simplement un peu plus de travail et passons moins de temps d' | ||
+ | |||
+ | Nous marquons le début et la fin de la transaction avec des instructions SQL : | ||
+ | |||
+ | BEGIN TRANSACTION; | ||
+ | ... | ||
+ | ... | ||
+ | COMMIT; | ||
+ | |||
+ | Nous pouvons entrer n' | ||
====== 12 ====== | ====== 12 ====== | ||
Ligne 241: | Ligne 250: | ||
This is unexpected—but it turns out that Firefox always arranges for invisible BEGIN and COMMIT instructions to be inserted into any SQL that is run. The error (correctly) says that you can't nest transactions.** | This is unexpected—but it turns out that Firefox always arranges for invisible BEGIN and COMMIT instructions to be inserted into any SQL that is run. The error (correctly) says that you can't nest transactions.** | ||
+ | Ajoutons donc un peu plus d' | ||
+ | |||
+ | Nous obtenons comme invite : | ||
+ | |||
+ | INSERT INTO nomTable [(liste-colonnes)] VALUES(liste-valeurs) | ||
+ | |||
+ | Compte tenu de notre tentative réussie avec une seule ligne, il semble raisonnable d' | ||
+ | Un de ces noms est une vraie personne (ci-dessus). | ||
+ | |||
+ | Cependant, lorsque nous tentons d' | ||
+ | |||
+ | C'est inattendu — mais il s' | ||
+ | |||
+ | **cadre orangé en haut de la page 18 :** | ||
+ | |||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
+ | INSERT INTO " | ||
====== 13 ====== | ====== 13 ====== | ||
Ligne 250: | Ligne 284: | ||
So far, we have managed to create just one table. It is only when we have several tables that we can map the relationships between them. You will be pleased to learn that the Firefox add-on allows you to import an initial data load if you have appropriate data available as CSV, XML or SQL source; it is also possible to export a table to these file types too. We still need to write the SQL statements to create the tables, but we can import our base data from spreadsheet(s).** | So far, we have managed to create just one table. It is only when we have several tables that we can map the relationships between them. You will be pleased to learn that the Firefox add-on allows you to import an initial data load if you have appropriate data available as CSV, XML or SQL source; it is also possible to export a table to these file types too. We still need to write the SQL statements to create the tables, but we can import our base data from spreadsheet(s).** | ||
+ | Aucun langage de programmation ne ferait jamais ça à votre place ; dans une situation réelle, vous voulez intercepter les erreurs, et soit les corriger, soit simplement les accepter comme des erreurs qui ne sont pas suffisamment graves pour provoquer l' | ||
+ | |||
+ | Dans ce cas, nous supprimons simplement les instructions BEGIN et COMMIT et cela fonctionne parfaitement. Il existe une commande SQL très simple pour afficher toutes les lignes et toutes les colonnes d'une table, et nous allons l' | ||
+ | |||
+ | Jusqu' | ||
====== 14 ====== | ====== 14 ====== | ||
Ligne 263: | Ligne 302: | ||
Since it would be meaningless to allow the entry of the address of someone who is not in the Tstudent table, we need to prevent this. This kind of problem is described as a “referential integrity issue,” and it could be prevented by relevant program coding. However, the problem is really intrinsic to our database design, and a database with dozens of tables would suffer many more referential integrity issues.** | Since it would be meaningless to allow the entry of the address of someone who is not in the Tstudent table, we need to prevent this. This kind of problem is described as a “referential integrity issue,” and it could be prevented by relevant program coding. However, the problem is really intrinsic to our database design, and a database with dozens of tables would suffer many more referential integrity issues.** | ||
+ | Pour Tadresse nous allons spécifier les colonnes comme suit : | ||
- | ====== 15 ====== | + | Notez que nous aurions pu spécifier deux colonnes pour notre clé primaire et la commande |
- | + | ||
- | **The solution lies in entering the data rules into the database, so that the database can enforce data integrity (note that although the same name of student_id was used in both the Tstudent and Taddress tables, this doesn' | + | |
- | + | ||
- | This is the situation alluded to earlier of a “foreign key”—here we would want any attempt to update Taddress to check that the student_id already exists in Tstudent. We can think of Tstudent as being the “parent” whilst the corresponding multiple address rows are “child” entries. Potential problems could also happen if we were to delete a row from the parent, but we can instruct the database to automatically delete all the child entries. | + | |
- | + | ||
- | Unfortunately, | + | |
- | It is important to type the PRAGMA foreign_keys=ON; | + | |
- | + | ||
- | + | ||
- | ====== 16 ====== | + | |
- | + | ||
- | **The correct syntax for the foreign key specification can be rather complicated. With a little practice, this is straightforward; | + | |
- | + | ||
- | DROP TABLE " | + | |
- | + | ||
- | CREATE TABLE " | + | |
- | + | ||
- | This will cause updates to check that the FOREIGN KEY(" | + | |
- | + | ||
- | + | ||
- | ====== 17 ====== | + | |
- | + | ||
- | **We can summarise the major constraints we can place on a column: | + | |
- | • NOT NULL | + | |
- | • UNIQUE | + | |
- | • PRIMARY KEY | + | |
- | • FOREIGN KEY | + | |
- | • CHECK e.g. CHECK(price > 0) | + | |
- | • DEFAULT (the value to be used if none is supplied) | + | |
- | + | ||
- | We can try and add an address line for a non-existent student:- | + | |
- | + | ||
- | Note that only two input parameters are needed | + | |
- | + | ||
- | This gives an error message—foreign key constraint failed. | + | |
- | + | ||
- | An attempt to add a valid student will succeed.** | + | |
- | + | ||
- | + | ||
- | ====== 18 ====== | + | |
- | + | ||
- | **We don't really care whether the line number of the address is 1, 2, 3, … or not—just that it is increasing. We have arranged for the database to do it and save some work in our program. | + | |
- | + | ||
- | A simple example (in Python) of adding just a few address lines would be: | + | |
- | + | ||
- | Note that the interface converts a Python “None” into an SQL “Null”, there is no error handling, and the address line sequence number is generated (correctly) by the database. | + | |
- | + | ||
- | We now need to create a new, super simple, table which will be a “codes file”; it associates exam codes with their titles. Since it's so simple, we can just type it into the “Execute SQL” area without any prompting. | + | |
- | + | ||
- | CREATE TABLE Texam_name (exam_id CHAR PRIMARY KEY NOT NULL UNIQUE, exam_title CHAR); | + | |
- | + | ||
- | Because we have the data available, we shall load the initial data from a CSV file (created from a spreadsheet): | + | |
- | + | ||
- | + | ||
- | ====== 19 ====== | + | |
- | + | ||
- | **We now have a number of tables and we are in a position to use one of the most powerful features of SQL—when we combine two or more tables together. To do this we use the JOIN keyword. There are two main varieties of JOIN available – by far the most common type of JOIN is a matching columns JOIN (technically an INNER JOIN). You can guess the name of the other kind of JOIN! | + | |
- | + | ||
- | When specifying our JOIN, a problem that sometimes occurs is that we have used the same name for a column in two tables – but perhaps it has different meanings – in which case we need to qualify the column name by table name. As an example: | + | |
- | + | ||
- | SELECT surname, forename, address FROM Tstudent AS S | + | |
- | JOIN Taddress AS A ON S.student_id = A.student_id; | + | |
- | + | ||
- | (The multiple lines are purely for readability), | + | |
- | + | ||
- | + | ||
- | ====== 20 ====== | + | |
- | + | ||
- | **It happens frequently that we make a habit of making up new names for the same thing, so in fact our student_id means the same thing in the two tables. As a shortcut we have the idea of a “NATURAL JOIN”—where any matching names are assumed to be required to be matched; so an equivalent to the previous JOIN is: | + | |
- | + | ||
- | SELECT surname, forename, address FROM Tstudent | + | |
- | NATURAL JOIN Taddress; | + | |
- | + | ||
- | Note that a NATURAL JOIN can give unexpected results if extra columns are added to the tables at a later date. | + | |
- | + | ||
- | If we expect to want to use our address list periodically, | + | |
- | + | ||
- | We can also create joins which are a JOIN of a table with itself, to create Views of a single table—perhaps to hide a particularly complex piece of SQL. It's also possible to join more than two tables in one statement—but then things tend to get complicated!** | + | |
- | + | ||
- | + | ||
- | ====== 21 ====== | + | |
- | + | ||
- | **If we have a very big database—many thousands of rows in several tables—performance will suffer. In this case, we should look at how we are using our database, especially with respect to JOINs, and specify the Index → Create index option. This is likely to speed up queries, at a small penalty for database updates (we have to maintain each additional index). | + | |
- | + | ||
- | The last major feature that can be used is the TRIGGER statement – where it is desirable that some database event should ' | + | |
- | + | ||
- | We still have one last table to construct—the one that links the students with their exams. | + | |
- | + | ||
- | Texams student_id exam_id score | + | |
- | + | ||
- | The exam score will be zero if they have not sat the exam yet. To access the score, we need the combination of student_id and exam_id to be our unique (primary key). This is a slightly tricky case, because we don't allow a student to take the same exam twice, but the data structure means that we need to accept duplicate student_id' | + | |
- | + | ||
- | + | ||
- | ====== 22 ====== | + | |
- | + | ||
- | **So Firefox produces: | + | |
- | + | ||
- | CREATE TABLE " | + | |
- | + | ||
- | We should really declare student_id to be a foreign key so that it is validated against Tstudent and similarly exam_id should be a foreign key so that it is validated against Texam_name. So we delete (with DROP Texams) and execute the following SQL; as you can see, it is effectively similar to our previous encounter with foreign keys. | + | |
- | + | ||
- | CREATE TABLE " | + | |
- | + | ||
- | CHECK (score >= 0), | + | |
- | + | ||
- | PRIMARY KEY (" | + | |
- | + | ||
- | FOREIGN KEY(" | + | |
- | + | ||
- | FOREIGN KEY(" | + | |
- | + | ||
- | (Actually, this is not quite correct as SQLite allows character values to be stored in numeric columns—so the CHECK statement would not work properly; we could fix this with a more complicated CHECK statement—but it wouldn' | + | |
- | + | ||
- | + | ||
- | ====== 23 ====== | + | |
- | + | ||
- | **We can enter all of the test cases using INSERT, and they should all behave properly. | + | |
- | + | ||
- | With our last table we are in a position to do something typical. The college has a few rather arbitrary rules, which change from time to time, so they don't really need to be enforced by the database. For example: “No student can enroll for M829, without achieving a pass in M823 previously”. This is easy to do in SQL with a little bit of decision in a program. | + | |
- | + | ||
- | As a slight variation, I've supplied a version that runs in a terminal screen; it could easily be converted to a BASH script. Many programs can have the database open, concurrently.** | + | |
- | + | ||
- | + | ||
- | ====== 24 ====== | + | |
- | + | ||
- | **jeremy@HECTOR: | + | |
- | + | ||
- | jeremy@HECTOR: | + | |
- | + | ||
- | SQLite version 3.7.9 2011-11-01 00:52:41 | + | |
- | + | ||
- | Enter " | + | |
- | + | ||
- | Enter SQL statements terminated with a ";" | + | |
- | + | ||
- | sqlite> SELECT count(*) FROM Texams WHERE (" | + | |
- | + | ||
- | | + | |
- | + | ||
- | 1 | + | |
- | + | ||
- | sqlite> INSERT INTO Texams VALUES(" | + | |
- | + | ||
- | sqlite> .exit | + | |
- | + | ||
- | jeremy@HECTOR: | + | |
- | + | ||
- | The SELECT count(*) … statement is an example of one of the many built-in “aggregate” functions – here the number of rows that meet the conditions in the WHERE conditional, | + | |
- | + | ||
- | + | ||
- | ====== 25 ====== | + | |
- | + | ||
- | **I shall give a number of references for more advanced use; but even if you want only a single keyed file or two—perhaps for an address book—a database is a big advance over some complex coding solution. | + | |
- | + | ||
- | References: | + | |
- | + | ||
- | http:// | + | |
- | + | ||
- | http:// | + | |
- | + | ||
- | http:// | + | |
- | + | ||
- | http:// | + | |
- | + | ||
- | http:// | + | |
- | + | ||
- | http:// | + | |
- | http:// | + | CREATE TABLE " |
- | http:// | + | Toutefois, nous avons choisi d' |
- | http://en.wikipedia.org/ | + | Comme il serait absurde de permettre de saisir l' |
+ | À suivre... |
store_data_safely/an_intro_to_sqlite.1380569781.txt.gz · Dernière modification : 2013/09/30 21:36 de fredphil91