<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<question type="category">
  <category>
    <text>$course$/QCM de NSI/Terminale/Bases de données et SQL</text>
  </category>
  <info format="html">
    <text><![CDATA[<p>Modèle relationnel (tables, attributs, clés primaires<br/>
et étrangères), contraintes d'intégrité, anomalies dans<br/>
un schéma, langage SQL (SELECT, FROM, WHERE, JOIN,<br/>
INSERT, UPDATE, DELETE), services rendus par un SGBD.</p>]]></text>
  </info>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q01 : Définition d'un SGBD</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Que désigne le sigle SGBD ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Un SGBD relationnel (SGBDR) ajoute la gestion du modèle<br/>
relationnel et du langage SQL. Tous les exemples cités<br/>
ci-dessus sont des SGBDR.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Stockage Garanti des Bases Distribuées</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sigle inventé.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Système de Génération Binaire de Données</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sigle inventé. SGBD est lié à la <strong>gestion</strong><br/>
des bases de données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Standard Général des Bibliothèques de Données</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sigle inventé.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Système de Gestion de Base de Données</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : un SGBD est un logiciel qui permet de<br/>
stocker, organiser, interroger et sécuriser des<br/>
données. Exemples : MySQL, PostgreSQL, SQLite, Oracle.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q02 : Vocabulaire du modèle relationnel</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Dans le modèle relationnel, comment appelle-t-on <strong>une ligne</strong><br/>
d'une table ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Vocabulaire du modèle relationnel : <strong>table</strong> (relation),<br/>
<strong>ligne</strong> (n-uplet, enregistrement), <strong>colonne</strong> (attribut),<br/>
<strong>domaine</strong> (type des valeurs), <strong>clé primaire</strong> (identifiant<br/>
unique).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un attribut</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un attribut est une <strong>colonne</strong> (un champ),<br/>
pas une ligne.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Un n-uplet (ou enregistrement)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : une ligne d'une table relationnelle est<br/>
un n-uplet (en français) ou <em>tuple</em> (en anglais), aussi<br/>
appelé enregistrement. Elle représente une instance<br/>
d'entité.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une clé</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une clé est une combinaison d'attributs qui<br/>
identifie de manière unique chaque ligne.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un domaine</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un domaine est l'ensemble des valeurs possibles<br/>
pour un attribut (par exemple, les entiers naturels<br/>
pour l'âge).</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q03 : Clé primaire</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle est la propriété fondamentale d'une <strong>clé primaire</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Une clé primaire est : (1) unique, (2) non nulle, (3) stable<br/>
dans le temps. Elle peut être composite (composée de<br/>
plusieurs colonnes) si aucune colonne unique ne suffit.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Elle identifie de manière unique chaque ligne de la table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la clé primaire est par définition<br/>
unique dans la table. Deux lignes ne peuvent jamais<br/>
avoir la même valeur de clé primaire.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle doit être un nombre entier</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une clé primaire peut être de n'importe quel<br/>
type (chaîne, code-barre, identifiant composite). Le<br/>
type entier est seulement le plus courant.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle peut prendre la valeur <code>NULL</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une clé primaire ne peut <strong>jamais</strong> être<br/>
<code>NULL</code>, sinon elle ne pourrait plus identifier une<br/>
ligne de manière unique.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle doit toujours être une seule colonne</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une clé primaire peut être <strong>composite</strong> (sur<br/>
plusieurs colonnes). Par exemple, dans une table<br/>
d'inscriptions, le couple <code>(eleve_id, cours_id)</code> peut<br/>
être une clé primaire composite.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q04 : Clé étrangère</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Que représente une <strong>clé étrangère</strong> dans une table ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les clés étrangères implémentent les <strong>relations</strong> entre<br/>
tables et permettent au SGBD de garantir l'<strong>intégrité<br/>
référentielle</strong> : on ne peut pas créer une commande pour<br/>
un client inexistant.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Un attribut qui référence la clé primaire d'une autre table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la clé étrangère établit un lien<br/>
relationnel entre deux tables. Par exemple, dans une<br/>
table <code>Commandes</code>, l'attribut <code>client_id</code> référence<br/>
la clé primaire de la table <code>Clients</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une clé qui ne peut pas être modifiée</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la modification est possible. Le terme<br/>
« étrangère » concerne la référence vers une autre<br/>
table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une clé importée d'un autre fichier</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : « étrangère » ne signifie pas « importée<br/>
d'un fichier ». Elle référence simplement une autre<br/>
<strong>table</strong> dans la même base.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un attribut crypté pour la sécurité</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucune notion de chiffrement dans le concept<br/>
de clé étrangère. C'est une notion structurelle, pas<br/>
de sécurité.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q05 : Syntaxe de base de SELECT</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle est la syntaxe SQL pour récupérer <strong>toutes</strong> les<br/>
colonnes de la table <code>eleves</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Bonne pratique : éviter <code>SELECT *</code> en production et lister<br/>
explicitement les colonnes nécessaires. Cela rend le code<br/>
plus robuste aux évolutions de schéma et plus clair.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la syntaxe <code>SELECT</code> requiert au minimum la<br/>
liste des colonnes (ou <code>*</code>) puis <code>FROM</code> pour la table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>GET ALL FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>GET</code> n'existe pas en SQL. La commande de<br/>
lecture est <code>SELECT</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>*</code> est le joker qui désigne toutes<br/>
les colonnes. <code>FROM</code> indique la table source.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>READ eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>READ</code> n'est pas un mot-clé SQL. La lecture<br/>
se fait avec <code>SELECT</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q06 : Filtrage avec WHERE</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour ne sélectionner que les élèves majeurs de la table<br/>
<code>eleves</code>, quelle requête utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Une requête SQL classique a la forme :<br/>
<code>SELECT colonnes FROM table WHERE condition</code>. Les<br/>
conditions multiples se combinent avec <code>AND</code>, <code>OR</code>, <code>NOT</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>FILTER eleves WHERE age &gt;= 18</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>FILTER</code> n'est pas la syntaxe SQL standard.<br/>
On utilise <code>SELECT ... WHERE</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves CONDITION age &gt;= 18</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>CONDITION</code> n'existe pas en SQL. C'est <code>WHERE</code><br/>
qui introduit la condition.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves WHERE age &gt;= 18</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>WHERE</code> introduit la condition de<br/>
filtrage. La syntaxe est <code>WHERE condition</code>, où<br/>
condition utilise les opérateurs SQL standard<br/>
(<code>=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code>, <code>&lt;&gt;</code>, <code>LIKE</code>, etc.).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves IF age &gt;= 18</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>IF</code> n'est pas un mot-clé SQL pour le<br/>
filtrage. Le filtre se fait avec <code>WHERE</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q07 : Tri avec ORDER BY</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour afficher les élèves par ordre alphabétique de leur<br/>
nom, on utilise :</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Pour trier par nom puis par prénom : <code>ORDER BY nom, prenom</code>.<br/>
Pour ordre décroissant : <code>ORDER BY nom DESC</code>. On peut<br/>
mélanger : <code>ORDER BY classe ASC, moyenne DESC</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves ARRANGE BY nom</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>ARRANGE BY</code> n'est pas du SQL valide.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves ORDER BY nom</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>ORDER BY</code> trie le résultat selon une<br/>
ou plusieurs colonnes. Par défaut, l'ordre est<br/>
ascendant (<code>ASC</code>). Pour un ordre descendant, ajouter<br/>
<code>DESC</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves SORTED nom</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>SORTED</code> n'existe pas en SQL.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM eleves SORT BY nom</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>SORT BY</code> n'est pas une syntaxe SQL. Le tri<br/>
se fait avec <code>ORDER BY</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q08 : Contraintes d'intégrité</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Qu'est-ce qu'une <strong>contrainte d'intégrité</strong> dans une base de<br/>
données relationnelle ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les contraintes d'intégrité sont <strong>vérifiées<br/>
automatiquement</strong> par le SGBD à chaque modification. Si<br/>
une opération les violerait, elle est rejetée. C'est une<br/>
garantie forte de cohérence.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un mot de passe pour accéder à une table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucun rapport avec l'authentification. Les<br/>
contraintes d'intégrité concernent la cohérence des<br/>
données, pas la sécurité d'accès.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Une règle qui restreint les valeurs admissibles dans la base, vérifiée par le SGBD</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : les contraintes garantissent la<br/>
cohérence des données. Exemples : <code>NOT NULL</code> (valeur<br/>
obligatoire), <code>UNIQUE</code> (pas de doublon), clé primaire,<br/>
clé étrangère, <code>CHECK</code> (condition arbitraire).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une copie de sauvegarde automatique</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucun rapport avec les sauvegardes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un index pour accélérer les requêtes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : les index sont des structures auxiliaires<br/>
pour la performance, pas des règles de cohérence.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q09 : Insertion d'une ligne</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle commande SQL ajoute une ligne dans une table ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les quatre commandes principales du SQL DML (Data<br/>
Manipulation Language) sont : <code>SELECT</code> (lire),<br/>
<code>INSERT</code> (créer), <code>UPDATE</code> (modifier), <code>DELETE</code> (supprimer).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>INSERT INTO eleves VALUES ('Alice', 17)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>INSERT INTO table VALUES (...)</code> est la<br/>
forme classique. On peut aussi préciser les colonnes :<br/>
<code>INSERT INTO eleves (nom, age) VALUES ('Alice', 17)</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>CREATE INTO eleves VALUES ('Alice', 17)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>CREATE</code> est utilisé pour créer une table<br/>
(<code>CREATE TABLE</code>), pas pour insérer une ligne.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>PUT INTO eleves VALUES ('Alice', 17)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>PUT</code> n'existe pas en SQL.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>ADD INTO eleves VALUES ('Alice', 17)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>ADD</code> n'est pas la syntaxe SQL standard pour<br/>
ajouter une ligne.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q10 : Valeurs atomiques</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Dans une base relationnelle correctement conçue, on<br/>
attend que chaque attribut contienne une valeur<br/>
<strong>atomique</strong>. Que signifie cette propriété ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Stocker des valeurs non atomiques (listes, couples,<br/>
tableaux) dans une cellule est une anomalie<br/>
fréquente. Cela empêche de filtrer ou de joindre<br/>
facilement la donnée et peut générer des<br/>
redondances et des incohérences.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La valeur doit être un entier</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucune contrainte de type. Une valeur<br/>
atomique peut être une chaîne, un booléen, un<br/>
flottant…</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La valeur n'est pas décomposable en plusieurs informations distinctes (par exemple, on ne stocke pas plusieurs numéros de téléphone dans une même cellule)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : un attribut comme<br/>
<code>telephones = "06 12 ; 06 34"</code> mélange deux<br/>
informations dans une cellule, ce qui rend les<br/>
requêtes difficiles. Il faut alors créer une<br/>
seconde table reliée par une clé étrangère.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La valeur ne peut jamais être modifiée</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : « atomique » ne signifie pas<br/>
« immuable ». Les valeurs peuvent évidemment<br/>
être mises à jour avec <code>UPDATE</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La valeur ne peut pas être nulle</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucun rapport. L'absence de valeur est<br/>
gérée par <code>NULL</code> ou par la contrainte<br/>
<code>NOT NULL</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q11 : Jointure entre deux tables</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour combiner les tables <code>commandes</code> et <code>clients</code> en<br/>
reliant <code>commandes.client_id</code> à <code>clients.id</code>, quelle<br/>
syntaxe utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Différents types de jointures : <code>INNER JOIN</code> (ne garde<br/>
que les lignes appariées), <code>LEFT JOIN</code> (garde toutes les<br/>
lignes de la table de gauche), <code>RIGHT JOIN</code> (symétrique),<br/>
<code>FULL JOIN</code> (les deux côtés).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT * FROM commandes JOIN clients ON commandes.client_id = clients.id</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : c'est une jointure <strong>interne</strong> explicite.<br/>
Seules les commandes ayant un client correspondant<br/>
apparaissent. Syntaxe préférée à la virgule depuis<br/>
SQL-92.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM commandes, clients</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : cette syntaxe produit le <strong>produit cartésien</strong><br/>
(toutes les paires possibles), sans condition de<br/>
jointure. Le résultat est rarement ce qu'on souhaite.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM commandes WITH clients</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>WITH</code> introduit des sous-requêtes nommées<br/>
(CTE), pas des jointures.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT * FROM commandes UNION clients</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>UNION</code> combine deux requêtes en empilant<br/>
leurs résultats (les lignes de l'une après l'autre).<br/>
Pour combiner colonnes côte à côte, c'est <code>JOIN</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q12 : Fonctions d'agrégation</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour calculer la <strong>moyenne des âges</strong> des élèves, quelle<br/>
requête utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les fonctions d'agrégation principales en SQL sont<br/>
<code>COUNT</code>, <code>SUM</code>, <code>AVG</code>, <code>MIN</code> et <code>MAX</code>. Elles<br/>
synthétisent une colonne entière en une seule<br/>
valeur dans le résultat de la requête.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT MOYENNE(age) FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : SQL utilise des mots-clés en anglais. La<br/>
version française n'existe pas.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT (age) FROM eleves AVERAGE</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la syntaxe <code>AVERAGE</code> après le <code>FROM</code> n'existe<br/>
pas. Les fonctions d'agrégation s'appliquent à<br/>
l'intérieur du <code>SELECT</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT MEAN(age) FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la fonction de moyenne en SQL standard<br/>
s'appelle <code>AVG</code>, pas <code>MEAN</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT AVG(age) FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>AVG</code> (<em>average</em>) calcule la moyenne<br/>
arithmétique. Les fonctions d'agrégation principales<br/>
sont <code>COUNT</code>, <code>SUM</code>, <code>AVG</code>, <code>MIN</code>, <code>MAX</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q13 : Combiner WHERE et ORDER BY</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle requête renvoie les noms des élèves majeurs,<br/>
classés par âge <strong>décroissant</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>L'ordre canonique des clauses dans une requête<br/>
d'interrogation est : <code>SELECT</code> … <code>FROM</code> … <code>WHERE</code> …<br/>
<code>ORDER BY</code> …. Le mot-clé <code>DESC</code> après <code>ORDER BY</code><br/>
indique un tri décroissant ; <code>ASC</code> (par défaut)<br/>
indique un tri croissant.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT nom FROM eleves ORDER BY age DESC WHERE age &gt;= 18</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : l'ordre des clauses est imposé en SQL.<br/>
<code>WHERE</code> se place avant <code>ORDER BY</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT nom FROM eleves WHERE age &gt;= 18 ORDER BY age DESC</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>WHERE</code> filtre les lignes<br/>
(majeurs), puis <code>ORDER BY age DESC</code> les trie par<br/>
âge décroissant.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT nom FROM eleves WHERE age &gt;= 18 ORDER BY age</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans le mot-clé <code>DESC</code>, le tri se fait<br/>
par défaut en ordre croissant.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT nom FROM eleves WHERE age &gt;= 18 SORT age DESC</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la clause <code>SORT</code> n'existe pas en SQL<br/>
standard. Il faut utiliser <code>ORDER BY</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q14 : Modification d'une ligne</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour augmenter de $1$ point la note de l'élève d'identifiant<br/>
$42$, quelle requête utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Toujours penser à mettre une clause <code>WHERE</code> sur les<br/>
<code>UPDATE</code> et <code>DELETE</code>. <strong>Sans elle, la modification s'applique<br/>
à toutes les lignes</strong> de la table, ce qui est rarement ce<br/>
qu'on veut et souvent catastrophique.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>MODIFY eleves SET note = note + 1 WHERE id = 42</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>MODIFY</code> n'est pas un mot-clé SQL standard.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>UPDATE eleves SET note = note + 1 WHERE id = 42</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>UPDATE</code> met à jour des lignes<br/>
existantes. La clause <code>SET</code> indique les modifications<br/>
et <code>WHERE</code> filtre les lignes affectées.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>UPDATE eleves WHERE id = 42 SET note = note + 1</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ordre incorrect des clauses. La syntaxe<br/>
standard est <code>UPDATE table SET ... WHERE ...</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>CHANGE eleves SET note = note + 1 WHERE id = 42</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>CHANGE</code> n'est pas un mot-clé SQL standard.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q15 : Suppression de doublons</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour obtenir la liste des <strong>classes différentes</strong> présentes<br/>
dans la table <code>eleves</code> (sans doublons), quelle requête<br/>
utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p><code>DISTINCT</code> agit sur l'ensemble des colonnes<br/>
sélectionnées. Par exemple,<br/>
<code>SELECT DISTINCT nom, prenom FROM eleves</code> ne renverra<br/>
qu'une ligne par couple (nom, prenom) distinct.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>SELECT DISTINCT classe FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>DISTINCT</code> élimine les doublons. Si<br/>
la table contient $30$ élèves de la classe « 1NSI »<br/>
et $25$ de « TNSI », la requête renvoie deux lignes :<br/>
« 1NSI » et « TNSI ».</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT classe DISTINCT FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>DISTINCT</code> se place <strong>avant</strong> la liste des<br/>
colonnes, juste après <code>SELECT</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT UNIQUE classe FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>UNIQUE</code> est utilisé pour les contraintes au<br/>
moment de la création de table, pas pour la sélection.<br/>
Le mot-clé pour la sélection est <code>DISTINCT</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>SELECT classe FROM eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans <code>DISTINCT</code>, le résultat contiendra une<br/>
entrée par élève, donc beaucoup de doublons.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q16 : Représenter une association multiple</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On souhaite représenter le fait qu'un élève peut<br/>
suivre <strong>plusieurs cours</strong> et qu'un cours peut<br/>
accueillir <strong>plusieurs élèves</strong>. Quel schéma<br/>
relationnel adopter ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Une association « plusieurs à plusieurs » se<br/>
représente par une table d'association qui contient<br/>
les clés étrangères des deux entités liées. C'est un<br/>
patron classique du modèle relationnel pour éviter<br/>
les redondances.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Deux tables avec une duplication des cours dans chaque ligne d'élève</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la duplication crée des redondances et<br/>
des anomalies de mise à jour si l'intitulé<br/>
d'un cours change.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une seule table <code>eleves</code> avec autant de colonnes <code>cours_1</code>, <code>cours_2</code>, <code>cours_3</code> qu'il y a de cours possibles</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ce schéma est rigide (il faut<br/>
modifier la structure si un nouveau cours<br/>
apparaît) et la plupart des cellules seront<br/>
vides.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une seule table contenant <code>eleve</code> et tous ses cours dans une même cellule</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : on viole la propriété d'atomicité des<br/>
attributs et on ne peut plus interroger<br/>
facilement les données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Trois tables <code>eleves(id, nom)</code>, <code>cours(id, intitule)</code> et <code>inscriptions(eleve_id, cours_id)</code> reliées par des clés étrangères</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : on isole chaque entité dans sa<br/>
table et on crée une table <strong>d'association</strong><br/>
dont chaque ligne représente une inscription<br/>
d'un élève à un cours.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q17 : Recherche avec LIKE</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour trouver tous les élèves dont le nom commence par "Du",<br/>
quelle requête utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les jokers de <code>LIKE</code> : <code>%</code> (zéro ou plus de caractères) et<br/>
<code>_</code> (un caractère exactement). Pour une recherche<br/>
insensible à la casse, certains SGBD acceptent <code>ILIKE</code><br/>
(PostgreSQL) ou <code>LIKE</code> avec <code>LOWER()</code> (portable).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>WHERE nom STARTS 'Du'</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>STARTS</code> n'est pas un mot-clé SQL standard.<br/>
Pour cette recherche, on utilise <code>LIKE</code> avec <code>%</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>WHERE nom LIKE 'Du%'</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>LIKE</code> permet la correspondance par<br/>
motif. Le caractère <code>%</code> représente n'importe quelle<br/>
séquence de caractères (zéro ou plus). Donc <code>'Du%'</code><br/>
correspond à "Du", "Dupont", "Dubois", etc.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>WHERE nom = 'Du'</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>=</code> teste l'égalité exacte. Cela ne<br/>
renverrait que les élèves dont le nom est <strong>exactement</strong><br/>
"Du", pas ceux qui commencent par "Du".</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>WHERE nom CONTAINS 'Du'</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>CONTAINS</code> est non standard (existant dans<br/>
certains SGBD pour la recherche plein texte). Le SQL<br/>
standard utilise <code>LIKE</code> avec des jokers.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q18 : Suppression d'une ligne</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Que fait la requête <code>DELETE FROM eleves;</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Toujours utiliser <code>WHERE</code> avec <code>DELETE</code>, sauf intention<br/>
explicite de tout vider. Beaucoup de SGBD permettent<br/>
d'imposer une clause <code>WHERE</code> obligatoire en mode<br/>
« <em>safe updates</em> » pour éviter les catastrophes.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Elle supprime toutes les lignes de la table <code>eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>DELETE</code> sans clause <code>WHERE</code> vide la<br/>
table (mais la structure reste). C'est l'erreur<br/>
classique en production. Pour supprimer la table<br/>
entière (structure incluse), il faut <code>DROP TABLE eleves</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle supprime la table entière (structure et contenu)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est <code>DROP TABLE</code> qui supprime la structure.<br/>
<code>DELETE FROM</code> ne touche que les lignes, pas le schéma.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle ne fait rien (manque de <code>WHERE</code>)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans <code>WHERE</code>, la requête s'applique à<br/>
<strong>toutes</strong> les lignes. Elle est syntaxiquement valide.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Elle lève une erreur SQL</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la syntaxe est valide. Aucune erreur n'est<br/>
levée : c'est précisément le piège.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q19 : Services rendus par un SGBD</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Lequel des éléments suivants n'est <strong>pas</strong> un<br/>
service rendu par un système de gestion de bases de<br/>
données ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les services principaux d'un SGBD sont la<br/>
persistance, la gestion des accès concurrents,<br/>
l'efficacité du traitement des requêtes et la<br/>
sécurisation des accès. Le programme officiel<br/>
demande de les <strong>identifier</strong>, sans en détailler le<br/>
fonctionnement interne.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La gestion des accès concurrents par plusieurs utilisateurs ou programmes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est bien un service du SGBD, qui évite<br/>
les incohérences quand plusieurs requêtes<br/>
modifient les mêmes données simultanément.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La persistance des données (les données survivent à l'arrêt du programme)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est bien un service du SGBD, qui assure<br/>
le stockage durable des données sur disque.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La compilation du code source d'un programme Python</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la compilation de code Python<br/>
n'a aucun rapport avec un SGBD. C'est le rôle de<br/>
l'interpréteur Python ou d'un compilateur, pas<br/>
du gestionnaire de bases de données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La sécurisation des accès (authentification, droits par utilisateur)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est bien un service du SGBD, qui<br/>
contrôle qui peut lire ou modifier quoi.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q20 : Intégrité référentielle</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle situation viole l'<strong>intégrité référentielle</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>L'intégrité référentielle est garantie par les<br/>
contraintes <code>FOREIGN KEY</code>. À la suppression d'un client,<br/>
on peut configurer <code>ON DELETE CASCADE</code> (supprimer aussi<br/>
les commandes), <code>ON DELETE RESTRICT</code> (interdire la<br/>
suppression s'il y a des commandes), etc.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Avoir deux clients avec le même nom</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ce n'est pas une violation tant que la clé<br/>
primaire (l'<code>id</code>) est unique. Le nom peut être en<br/>
double.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Insérer une commande avec un <code>client_id</code> qui n'existe pas dans la table <code>clients</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la clé étrangère <code>client_id</code> doit<br/>
pointer vers une ligne existante de la table<br/>
<code>clients</code>. Sinon, on a une référence orpheline,<br/>
violation typique de l'intégrité référentielle.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Insérer une commande sans préciser la quantité</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est une violation de contrainte <code>NOT NULL</code>,<br/>
pas d'intégrité référentielle. Cette dernière concerne<br/>
les références entre tables.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Trier les commandes par date</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un tri ne viole aucune contrainte.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q21 : Sous-requête</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Que renvoie cette requête ?</p>
<pre><code>SELECT nom FROM eleves
WHERE moyenne &gt; (SELECT AVG(moyenne) FROM eleves);</code></pre>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>On peut utiliser <code>&gt;=</code>, <code>&lt;</code>, <code>=</code>, <code>IN</code> avec une sous-requête.<br/>
La sous-requête est exécutée <strong>une fois</strong> ici (elle ne<br/>
dépend pas de la ligne courante), donc le SGBD optimise<br/>
automatiquement.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Les moyennes des élèves au-dessus de zéro</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la condition <code>&gt;</code> ne porte pas sur zéro mais<br/>
sur la valeur de la sous-requête.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une erreur (sous-requête non autorisée)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : les sous-requêtes sont parfaitement<br/>
autorisées en SQL. C'est une fonctionnalité<br/>
essentielle.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La moyenne des moyennes des élèves</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>AVG(moyenne)</code> calcule effectivement la<br/>
moyenne des moyennes, mais la requête principale<br/>
renvoie les <strong>noms</strong> des élèves dépassant cette<br/>
moyenne, pas le calcul lui-même.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Les noms des élèves dont la moyenne est strictement supérieure à la moyenne de la classe</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la sous-requête calcule la moyenne<br/>
globale, et la requête principale filtre les élèves<br/>
au-dessus. C'est un usage très courant des<br/>
sous-requêtes pour comparer à un agrégat.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q22 : Détection d'une redondance</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Une table <code>commandes(id, client_id, nom_client, prenom_client, produit, prix)</code><br/>
pose un problème classique de schéma. Lequel ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>La normalisation vise à éliminer les redondances pour<br/>
garantir la <strong>cohérence</strong>. Si on stocke le nom du client<br/>
dans chaque commande et que le client se marie, il faut<br/>
mettre à jour toutes ses commandes, risqué et coûteux.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La clé primaire est mal choisie</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>id</code> est un choix raisonnable de clé primaire<br/>
pour des commandes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Les informations du client (nom, prénom) sont dupliquées à chaque commande, ce qui crée des incohérences potentielles si les noms sont mal mis à jour</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : c'est une <strong>redondance</strong><br/>
classique. Le nom et le prénom dépendent de<br/>
<code>client_id</code>, pas de l'<code>id</code> de commande. Il<br/>
faudrait les mettre dans une table <code>clients</code><br/>
séparée et conserver uniquement la clé<br/>
étrangère <code>client_id</code> dans <code>commandes</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Le prix devrait être stocké séparément</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : le prix peut varier d'une commande à l'autre<br/>
(promotions, historiques) et a sa place dans <code>commandes</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La table contient trop de colonnes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : le nombre de colonnes n'est pas un problème<br/>
en soi. Le problème est ailleurs.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q23 : Différence entre INNER et LEFT JOIN</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle est la différence entre <code>INNER JOIN</code> et <code>LEFT JOIN</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Le <code>JOIN</code> simple (équivalent de <code>INNER JOIN</code>)<br/>
apparie les lignes selon la condition <code>ON</code>. Le<br/>
<code>LEFT JOIN</code> étend ce comportement en conservant<br/>
aussi les lignes de gauche sans correspondance, en<br/>
les complétant par des <code>NULL</code> côté droit.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>INNER JOIN</code> ne garde que les paires appariées ; <code>LEFT JOIN</code> garde toutes les lignes de la table de gauche, complétées par <code>NULL</code> à droite si aucune correspondance</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : pour lister tous les clients avec<br/>
leurs commandes (ou pas), on utilise <code>LEFT JOIN</code>. Avec<br/>
<code>INNER JOIN</code>, les clients sans commande disparaissent<br/>
du résultat.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Aucune, ce sont des synonymes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ils diffèrent sur la gestion des lignes non<br/>
appariées de la table de gauche.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>LEFT JOIN</code> ne fonctionne que sur des tables triées</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucune contrainte de tri n'est requise pour<br/>
un <code>LEFT JOIN</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>INNER JOIN</code> est plus rapide que <code>LEFT JOIN</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la performance dépend du SGBD et du contexte.<br/>
La différence sémantique est ce qui compte avant<br/>
tout.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q24 : Problème de concurrence</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Sans isolation des transactions, deux transactions<br/>
simultanées qui modifient le même compte bancaire peuvent<br/>
provoquer :</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>La gestion des accès concurrents est l'un des<br/>
services principaux d'un SGBD. Le système prend en<br/>
charge l'enchaînement des opérations pour garantir<br/>
la cohérence des données, même quand plusieurs<br/>
utilisateurs ou programmes les manipulent en même<br/>
temps.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Une perte de mise à jour : l'effet d'une transaction est annulé par l'autre, faisant disparaître un dépôt</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : si T1 lit le solde ($1000$), puis T2<br/>
lit aussi ($1000$), puis T1 ajoute $100$ et écrit<br/>
$1100$, puis T2 ajoute $50$ et écrit $1050$, le dépôt<br/>
de T1 est perdu. C'est la <strong>perte de mise à jour</strong><br/>
classique.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une erreur de syntaxe SQL</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la syntaxe est correcte. Le problème est de<br/>
<strong>cohérence</strong>, pas syntaxique.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une duplication automatique des données</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucune duplication automatique. C'est plutôt<br/>
de la perte d'information.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une accélération de l'exécution des deux transactions</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans isolation, on a au contraire des<br/>
incohérences. La gestion correcte est plus lente mais<br/>
fiable.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q25 : Index</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pourquoi crée-t-on des <strong>index</strong> sur les colonnes<br/>
fréquemment utilisées dans des <code>WHERE</code> ou des jointures ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Compromis classique : un index accélère <strong>les lectures</strong><br/>
mais ralentit <strong>les écritures</strong> (chaque insertion ou mise<br/>
à jour doit aussi mettre à jour l'index). On crée donc des<br/>
index uniquement sur les colonnes vraiment souvent<br/>
interrogées.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Pour accélérer la recherche en évitant un parcours complet de la table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : un index est une structure<br/>
auxiliaire qui permet de retrouver rapidement<br/>
les lignes correspondant à une valeur donnée,<br/>
sans avoir à parcourir toute la table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Pour économiser de l'espace de stockage</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est l'inverse, un index <strong>consomme</strong> de<br/>
l'espace supplémentaire. Le bénéfice est ailleurs.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Pour rendre les données automatiquement triées</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un index trie en interne, mais les données<br/>
de la table elle-même restent dans leur ordre<br/>
original.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Pour chiffrer les données sensibles</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : les index sont des structures de performance,<br/>
pas de sécurité.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q26 : Regroupement avec GROUP BY</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour obtenir le <strong>nombre d'élèves par classe</strong> dans la<br/>
table <code>eleves(id, nom, classe)</code>, quelle requête utiliser ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Schéma général : <code>SELECT colonne, AGREGATION(...) FROM<br/>
table GROUP BY colonne</code>. Toutes les colonnes du <code>SELECT</code><br/>
qui ne sont pas dans une fonction d'agrégation doivent<br/>
apparaître dans le <code>GROUP BY</code>. C'est la règle dite<br/>
« des colonnes visibles ».</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(*)
FROM eleves;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans <code>GROUP BY</code>, mélanger une colonne et une<br/>
fonction d'agrégation provoque une erreur SQL ou un<br/>
résultat incohérent (selon le SGBD). Il faut grouper<br/>
explicitement par <code>classe</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT DISTINCT classe, COUNT(*)
FROM eleves;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>DISTINCT</code> élimine les doublons après calcul,<br/>
il ne sert pas à regrouper pour appliquer une<br/>
agrégation. La syntaxe correcte est <code>GROUP BY</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(eleves)
FROM eleves
GROUP BY classe;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>COUNT(eleves)</code> n'est pas valide :<br/>
<code>eleves</code> est le nom de la table, pas une colonne.<br/>
Pour compter les lignes, on utilise <code>COUNT(*)</code> ou une<br/>
colonne précise (<code>COUNT(id)</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(*)
FROM eleves
GROUP BY classe;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>GROUP BY</code> regroupe les lignes par<br/>
valeur distincte de <code>classe</code>. La fonction d'agrégation<br/>
<code>COUNT(*)</code> compte les lignes de chaque groupe. Le<br/>
résultat est une ligne par classe avec son effectif.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q27 : HAVING vs WHERE</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour ne garder que les classes ayant <strong>au moins<br/>
$25$ élèves</strong>, on doit filtrer un résultat agrégé. Quelle<br/>
est la requête correcte ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Ordre canonique des clauses :<br/>
<code>SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY</code>.<br/>
Mnémonique : <code>WHERE</code> filtre les lignes individuelles avant<br/>
regroupement ; <code>HAVING</code> filtre les groupes après agrégation.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT classe
FROM eleves
GROUP BY classe
WHERE COUNT(*) &gt;= 25;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la clause <code>WHERE</code> doit toujours apparaître<br/>
<strong>avant</strong> <code>GROUP BY</code> dans la syntaxe SQL. De plus,<br/>
on ne peut pas y mettre une fonction d'agrégation.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(*)
FROM eleves
WHERE COUNT(*) &gt;= 25
GROUP BY classe;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>WHERE</code> ne peut pas porter sur une fonction<br/>
d'agrégation, qui n'est calculée qu'<strong>après</strong> le<br/>
regroupement. Cette requête échoue avec une erreur<br/>
SQL. C'est précisément le rôle de <code>HAVING</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(*)
FROM eleves
HAVING classe COUNT(*) &gt;= 25;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la syntaxe est invalide. <code>HAVING</code> doit<br/>
contenir une condition logique, et il manque le<br/>
<code>GROUP BY</code> qui définit les groupes sur lesquels<br/>
porte le <code>HAVING</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>SELECT classe, COUNT(*)
FROM eleves
GROUP BY classe
HAVING COUNT(*) &gt;= 25;</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>HAVING</code> filtre les groupes après<br/>
agrégation, contrairement à <code>WHERE</code> qui filtre les<br/>
lignes avant agrégation. Pour porter sur le résultat<br/>
de <code>COUNT(*)</code>, il faut utiliser <code>HAVING</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q28 : Propriétés ACID</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Les propriétés ACID des transactions garantissent leur<br/>
bon comportement dans un SGBD. Que désigne le « C » de<br/>
ACID ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les quatre propriétés ACID sont : <strong>Atomicité</strong> (tout<br/>
ou rien), <strong>Cohérence</strong> (contraintes respectées),<br/>
<strong>Isolation</strong> (transactions concurrentes invisibles<br/>
les unes aux autres), <strong>Durabilité</strong> (modifications<br/>
persistées même en cas de panne). Indispensable pour<br/>
les bases métier (banque, santé, stock).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Compression</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la compression est une optimisation de<br/>
stockage, sans rapport avec les transactions.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Confidentialité</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la confidentialité relève de la sécurité<br/>
(chiffrement, contrôle d'accès), pas des propriétés<br/>
ACID des transactions. Ce sont deux dimensions<br/>
différentes du SGBD.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Connexion</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la connexion à la base est un mécanisme<br/>
d'accès, pas une propriété des transactions. Le<br/>
« C » désigne une propriété logique des transactions.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Cohérence</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la <strong>cohérence</strong> garantit qu'une<br/>
transaction fait passer la base d'un état cohérent<br/>
(toutes les contraintes respectées) à un autre état<br/>
cohérent. Si une transaction violerait une<br/>
contrainte d'intégrité, elle est rejetée<br/>
intégralement.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q29 : DROP, DELETE, TRUNCATE</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quelle est la différence entre <code>DROP TABLE eleves</code>,<br/>
<code>DELETE FROM eleves</code> et <code>TRUNCATE TABLE eleves</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Bonne pratique : utiliser <code>DELETE FROM ... WHERE</code> pour<br/>
des suppressions ciblées et sécurisées ; <code>TRUNCATE</code> pour<br/>
vider rapidement une table en conservant son schéma ;<br/>
<code>DROP TABLE</code> uniquement quand on veut effectivement se<br/>
débarrasser de la table elle-même. Toujours sauvegarder<br/>
avant <code>DROP</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Aucune n'est valide en SQL standard</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : les trois sont des commandes SQL valides.<br/>
<code>TRUNCATE</code> est légèrement moins répandu que les<br/>
deux autres, mais reste standard dans la plupart<br/>
des SGBD relationnels.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>DROP</code> et <code>DELETE</code> sont identiques ; seul<br/>
<code>TRUNCATE</code> est différent (il vide aussi les<br/>
fichiers de log)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>DROP TABLE</code> et <code>DELETE FROM</code> ne sont<br/>
<strong>pas</strong> équivalents. Le premier supprime la<br/>
structure de la table ; le second ne supprime<br/>
que les lignes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Les trois commandes sont équivalentes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : elles ont des effets très différents,<br/>
comme le détaille la bonne réponse. Confondre<br/>
<code>DROP</code> et <code>DELETE</code> peut être catastrophique en<br/>
production : <code>DROP</code> supprime tout, structure<br/>
comprise.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>DROP TABLE</code> supprime la table entière (structure et<br/>
contenu) ; <code>DELETE FROM</code> (sans <code>WHERE</code>) supprime<br/>
toutes les lignes mais conserve la structure (les<br/>
contraintes et les types restent) ; <code>TRUNCATE TABLE</code><br/>
vide rapidement le contenu en conservant la<br/>
structure (souvent plus rapide que <code>DELETE</code>)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : trois commandes très différentes.<br/>
<code>DROP</code> est destructif sur le schéma : la table<br/>
n'existe plus du tout après. <code>DELETE</code> est une<br/>
opération transactionnelle au cas par cas (logge<br/>
chaque suppression). <code>TRUNCATE</code> est une opération<br/>
en bloc, sans logging détaillé, généralement plus<br/>
rapide pour vider une grosse table.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q30 : Trace d'une requête SELECT avec WHERE</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On considère la table <code>eleves</code> suivante :</p>
<p>| id | nom    | classe | moyenne |<br/>
|----|--------|--------|---------|<br/>
| 1  | Alice  | 1A     | 14.5    |<br/>
| 2  | Bob    | 1B     | 9.0     |<br/>
| 3  | Chloé  | 1A     | 16.0    |<br/>
| 4  | David  | 1B     | 13.0    |<br/>
| 5  | Émma   | 1A     | 11.5    |</p>
<p>Que renvoie la requête suivante ?</p>
<pre><code>SELECT nom, moyenne
FROM eleves
WHERE classe = '1A' AND moyenne &gt;= 12
ORDER BY moyenne DESC;</code></pre>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Méthode systématique pour évaluer une requête<br/>
SQL : (1) appliquer le filtre <code>WHERE</code> pour ne<br/>
conserver que les lignes pertinentes ; (2)<br/>
projeter sur les colonnes du <code>SELECT</code> ; (3)<br/>
trier selon <code>ORDER BY</code> si présent. Cette<br/>
séquence d'étapes est l'algèbre relationnelle en<br/>
action.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Cinq lignes (toutes les lignes de la table)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : on a oublié le filtrage par <code>WHERE</code>.<br/>
Sans filtre, on aurait bien toutes les<br/>
lignes, mais ici la requête restreint aux<br/>
élèves de <code>1A</code> avec une moyenne d'au moins<br/>
$12$.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Trois lignes : <code>('Alice', 14.5)</code>,<br/>
<code>('Chloé', 16.0)</code>, <code>('Émma', 11.5)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Émma est en <code>1A</code> mais sa moyenne<br/>
($11{,}5$) est inférieure à $12$, donc elle<br/>
ne satisfait pas la condition <code>moyenne &gt;= 12</code>.<br/>
De plus, l'ordre n'est pas décroissant ici.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Deux lignes : <code>('Chloé', 16.0)</code> puis<br/>
<code>('Alice', 14.5)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse. Étape 1, le filtre<br/>
<code>WHERE classe = '1A' AND moyenne &gt;= 12</code><br/>
retient les élèves de la classe <code>1A</code> avec<br/>
une moyenne d'au moins $12$ : Alice ($14{,}5$)<br/>
et Chloé ($16$). Émma est en <code>1A</code> mais sa<br/>
moyenne ($11{,}5$) ne satisfait pas la<br/>
deuxième condition. Étape 2, on ne garde<br/>
que les colonnes <code>nom</code> et <code>moyenne</code>. Étape 3,<br/>
on trie par <code>moyenne DESC</code> : Chloé d'abord,<br/>
puis Alice.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une seule ligne : <code>('Chloé', 16.0)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Alice satisfait elle aussi les deux<br/>
conditions ($14{,}5 \geq 12$ et classe<br/>
<code>1A</code>). Elle doit donc apparaître dans le<br/>
résultat, après Chloé du fait du tri<br/>
décroissant.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q31 : Trace d'une jointure</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On dispose des deux tables suivantes :</p>
<p>Table <code>clients</code> :</p>
<p>| id | nom    |<br/>
|----|--------|<br/>
| 1  | Alice  |<br/>
| 2  | Bob    |<br/>
| 3  | Chloé  |</p>
<p>Table <code>commandes</code> :</p>
<p>| id | client_id | produit  |<br/>
|----|-----------|----------|<br/>
| 10 | 1         | Livre    |<br/>
| 11 | 2         | Cahier   |<br/>
| 12 | 1         | Stylo    |</p>
<p>Combien de lignes renvoie la requête suivante ?</p>
<pre><code>SELECT c.nom, cmd.produit
FROM clients c
JOIN commandes cmd ON c.id = cmd.client_id;</code></pre>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Pour faire apparaître Chloé (qui n'a aucune<br/>
commande) dans le résultat, il faudrait<br/>
utiliser un <code>LEFT JOIN</code>. La ligne<br/>
correspondante aurait alors <code>NULL</code> dans la<br/>
colonne <code>cmd.produit</code>. Cela permet de<br/>
répondre à la question « tous les clients,<br/>
avec leurs commandes éventuelles ».</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>2 lignes (une seule par client présent dans<br/>
les commandes)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Alice a <strong>deux</strong> commandes, donc<br/>
elle apparaît deux fois dans le résultat<br/>
(avec <code>'Livre'</code> et avec <code>'Stylo'</code>). La<br/>
jointure ne fusionne pas les commandes<br/>
d'un même client.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>3 lignes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la jointure interne (<code>JOIN</code>,<br/>
synonyme de <code>INNER JOIN</code>) ne garde que les<br/>
paires <code>(client, commande)</code> où la condition<br/>
<code>c.id = cmd.client_id</code> est vraie. Alice<br/>
(id $1$) a deux commandes ($10$ et $12$),<br/>
Bob (id $2$) en a une, Chloé n'en a aucune<br/>
et disparaît du résultat. Total : trois<br/>
lignes. Le résultat est :<br/>
<code>('Alice', 'Livre')</code>, <code>('Bob', 'Cahier')</code>,<br/>
<code>('Alice', 'Stylo')</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>9 lignes (le produit cartésien $3 \times 3$)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ce serait le résultat sans la<br/>
condition <code>ON c.id = cmd.client_id</code>. Avec<br/>
la condition, on ne garde que les paires<br/>
cohérentes, soit trois lignes ici. Le<br/>
produit cartésien apparaît avec<br/>
<code>FROM clients, commandes</code> (sans <code>JOIN</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>4 lignes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : seules trois commandes existent,<br/>
donc au plus trois lignes peuvent<br/>
apparaître. Une ligne supplémentaire<br/>
n'apparaîtrait que si l'on utilisait un<br/>
<code>LEFT JOIN</code> qui inclurait Chloé sans<br/>
commande (avec <code>NULL</code> côté commandes).</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q32 : GROUP BY avec HAVING en pratique</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Avec la table <code>eleves(id, nom, classe, moyenne)</code><br/>
contenant trente élèves répartis entre trois<br/>
classes (<code>1A</code>, <code>1B</code>, <code>1C</code>), que renvoie la<br/>
requête suivante ?</p>
<pre><code>SELECT classe, AVG(moyenne) AS moy_classe
FROM eleves
GROUP BY classe
HAVING AVG(moyenne) &gt; 12
ORDER BY moy_classe DESC;</code></pre>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Distinction essentielle : <code>WHERE</code> filtre les<br/>
lignes individuelles <strong>avant</strong> l'agrégation ;<br/>
<code>HAVING</code> filtre les groupes <strong>après</strong><br/>
l'agrégation. Si on voulait restreindre aux<br/>
élèves majeurs avant de calculer les moyennes,<br/>
on aurait combiné les deux :<br/>
<code>WHERE age &gt;= 18 ... HAVING AVG(moyenne) &gt; 12</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La liste des classes dont la moyenne de<br/>
la classe est strictement supérieure à<br/>
$12$, avec leur moyenne, triée par<br/>
moyenne décroissante</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse. Étape 1, <code>GROUP BY classe</code><br/>
regroupe les élèves par classe. Étape 2,<br/>
<code>AVG(moyenne)</code> calcule la moyenne de chaque<br/>
groupe. Étape 3, <code>HAVING AVG(moyenne) &gt; 12</code><br/>
filtre les groupes (et non les lignes<br/>
individuelles) selon cette condition.<br/>
Étape 4, <code>ORDER BY moy_classe DESC</code> trie<br/>
le résultat.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une erreur SQL, car on ne peut pas mettre<br/>
un alias dans <code>ORDER BY</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : SQL autorise tout à fait<br/>
d'utiliser un alias défini dans le<br/>
<code>SELECT</code> (ici <code>moy_classe</code>) au sein de<br/>
<code>ORDER BY</code>. La requête est valide.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Toutes les classes, avec la somme des<br/>
moyennes des élèves</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la fonction utilisée est <code>AVG</code><br/>
(moyenne), pas <code>SUM</code> (somme). Les deux<br/>
fonctions d'agrégation sont distinctes.<br/>
De plus, le <code>HAVING</code> filtrerait certaines<br/>
classes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La liste des élèves dont la moyenne<br/>
individuelle est supérieure à $12$</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est ce que ferait un simple<br/>
<code>WHERE moyenne &gt; 12</code> sans <code>GROUP BY</code>. Ici,<br/>
la fonction d'agrégation <code>AVG(moyenne)</code><br/>
combinée à <code>GROUP BY classe</code> calcule la<br/>
moyenne <strong>par classe</strong>, pas par élève.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q33 : Notion de vue</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Une <strong>vue</strong> (<code>VIEW</code>) en SQL est :</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les vues facilitent aussi la <strong>sécurité</strong> : on<br/>
peut accorder l'accès à une vue qui masque<br/>
certaines colonnes sensibles, sans donner<br/>
accès aux tables sous-jacentes. Variante<br/>
avancée : la <strong>vue matérialisée</strong> stocke<br/>
effectivement le résultat, et est rafraîchie<br/>
périodiquement ; elle combine vue et cache.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Une requête nommée dont le résultat se<br/>
comporte comme une table virtuelle :<br/>
chaque interrogation de la vue<br/>
réexécute la requête sous-jacente sur les<br/>
données actuelles</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : on définit une vue avec<br/>
<code>CREATE VIEW majeurs AS SELECT ... FROM<br/>
eleves WHERE age &gt;= 18;</code>. Ensuite,<br/>
<code>SELECT * FROM majeurs</code> renvoie le résultat<br/>
actualisé. Avantages : factoriser des<br/>
requêtes complexes, masquer certaines<br/>
colonnes (sécurité), simplifier l'écriture<br/>
des requêtes. La vue ne stocke pas les<br/>
données, elle stocke la requête.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une représentation graphique des relations<br/>
entre les tables</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une représentation graphique<br/>
s'appelle un <strong>schéma</strong> ou un diagramme<br/>
entité-association, pas une vue. La vue est<br/>
une notion logique (une requête nommée),<br/>
pas une représentation visuelle.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un type particulier d'index pour accélérer<br/>
les recherches</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un index est une structure<br/>
auxiliaire de performance ; une vue est une<br/>
requête nommée. Ces deux notions sont<br/>
totalement distinctes, même si certains<br/>
SGBD permettent des « vues matérialisées »<br/>
qui s'apparentent à un index.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une copie figée des données à un instant<br/>
donné</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ce serait une <strong>table</strong> (par<br/>
exemple créée via <code>CREATE TABLE ... AS<br/>
SELECT ...</code>). La vue, elle, ne contient pas<br/>
de données : elle contient une requête,<br/>
réévaluée à chaque interrogation pour<br/>
refléter l'état courant des tables source.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q34 : Lecture d'un schéma relationnel</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On considère le schéma relationnel suivant :</p>
<pre><code>eleves(id_eleve, nom, prenom, id_classe#)
classes(id_classe, niveau, salle)
notes(id_eleve#, id_devoir#, note)
devoirs(id_devoir, matiere, date)</code></pre>
<p>Le <code>#</code> désigne une clé étrangère. Quelle<br/>
affirmation est correcte ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Méthode pour lire un schéma relationnel : (1)<br/>
identifier la clé primaire de chaque table<br/>
(souvent soulignée ou notée en premier) ; (2)<br/>
repérer les clés étrangères (notées <code>#</code>,<br/>
soulignées en pointillés, ou en italique selon<br/>
la convention) ; (3) interpréter les<br/>
cardinalités. Ici, l'association <code>notes</code> est<br/>
une <strong>association n-aire</strong> typique, qui ne<br/>
peut pas se modéliser par une simple clé<br/>
étrangère ajoutée à une table existante.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La table <code>eleves</code> n'a pas de lien avec<br/>
<code>classes</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la colonne <code>id_classe#</code> dans<br/>
<code>eleves</code> est précisément une clé<br/>
étrangère qui pointe vers <code>classes</code>, ce<br/>
qui établit le lien « un élève appartient<br/>
à une classe ».</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>On peut avoir plusieurs élèves avec le<br/>
même <code>id_eleve</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>id_eleve</code> est la clé primaire de<br/>
la table <code>eleves</code>, donc unique par<br/>
définition. Deux élèves différents ne<br/>
peuvent pas partager la même valeur de<br/>
<code>id_eleve</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Pour ajouter une note dans <code>notes</code>, il<br/>
n'est pas nécessaire que l'élève existe<br/>
dans <code>eleves</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la clé étrangère <code>id_eleve#</code> dans<br/>
<code>notes</code> impose que la valeur référence un<br/>
élève existant. Insérer une note pour un<br/>
élève inexistant viole l'intégrité<br/>
référentielle et le SGBD rejette<br/>
l'opération.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La table <code>notes</code> a une clé primaire<br/>
composite <code>(id_eleve, id_devoir)</code>, et ses<br/>
deux composantes sont des clés étrangères<br/>
référençant respectivement <code>eleves</code> et<br/>
<code>devoirs</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : c'est la lecture correcte<br/>
du schéma. La table <code>notes</code> représente une<br/>
association ternaire (un élève, un devoir,<br/>
une note). La clé primaire composite<br/>
garantit l'unicité (un élève ne peut avoir<br/>
qu'une note par devoir), et les clés<br/>
étrangères assurent l'intégrité<br/>
référentielle (on ne peut pas mettre une<br/>
note pour un élève ou un devoir<br/>
inexistants).</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q35 : Injection SQL</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Un programme construit la requête SQL suivante<br/>
en concaténant directement la chaîne<br/>
<code>nom_saisi</code> reçue de l'utilisateur :</p>
<pre><code>requete = "SELECT * FROM users WHERE nom = '" + nom_saisi + "';"</code></pre>
<p>Si l'utilisateur saisit<br/>
<code>' OR '1'='1</code>, que se passe-t-il ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>L'injection SQL reste, en 2026, l'une des<br/>
vulnérabilités les plus exploitées dans les<br/>
applications web. La parade est connue depuis<br/>
longtemps : ne <strong>jamais</strong> construire une<br/>
requête SQL par concaténation de chaînes<br/>
utilisateur, mais utiliser systématiquement<br/>
des <strong>requêtes préparées</strong> où les paramètres<br/>
sont passés séparément<br/>
(<code>cursor.execute("... WHERE nom = ?", (nom_saisi,))</code>).<br/>
Le SGBD échappe alors automatiquement les<br/>
caractères dangereux.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Le SGBD détecte l'injection et rejette la<br/>
requête</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la requête est syntaxiquement<br/>
parfaitement valide. Le SGBD n'a aucun<br/>
moyen de détecter qu'elle vient d'une<br/>
concaténation dangereuse plutôt que d'une<br/>
intention légitime. C'est précisément ce<br/>
qui rend l'injection SQL si pernicieuse.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Python lève une exception au moment de la<br/>
concaténation</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Python concatène sans aucun<br/>
problème les chaînes, quel que soit leur<br/>
contenu. Aucune exception n'est levée.<br/>
C'est précisément le drame : tout se passe<br/>
silencieusement.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La requête devient<br/>
<code>SELECT * FROM users WHERE nom = '' OR '1'='1';</code>,<br/>
ce qui sélectionne toutes les lignes<br/>
de la table : c'est une injection SQL</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la concaténation naïve fait<br/>
sortir la chaîne saisie de son rôle de<br/>
simple donnée et l'injecte dans la<br/>
structure SQL. La condition <code>'1'='1'</code><br/>
étant toujours vraie, l'opérateur <code>OR</code> la<br/>
fait court-circuiter le filtre. C'est la<br/>
forme la plus simple d'injection SQL,<br/>
célèbre attaque qui a touché de nombreux<br/>
sites mal protégés. La parade standard :<br/>
utiliser des <strong>requêtes préparées</strong> avec<br/>
des paramètres liés<br/>
(<code>cursor.execute(req, (nom_saisi,))</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La requête ne retourne aucune ligne</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est l'inverse. La condition<br/>
<code>'1'='1'</code> étant toujours vraie, <strong>toutes</strong><br/>
les lignes de la table sont retournées,<br/>
y compris des données potentiellement<br/>
sensibles que l'utilisateur ne devrait<br/>
pas voir.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Bases de données et SQL — Q36 : Trace d'un UPDATE ciblé</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On part de la table <code>comptes</code> suivante :</p>
<p>| id | titulaire | solde |<br/>
|----|-----------|-------|<br/>
| 1  | Alice     | 1000  |<br/>
| 2  | Bob       | 500   |<br/>
| 3  | Chloé     | 2000  |</p>
<p>On exécute la requête suivante :</p>
<pre><code>UPDATE comptes
SET solde = solde * 1.05
WHERE solde &gt;= 1000;</code></pre>
<p>Quel est le contenu de la table après<br/>
exécution ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Schéma général d'un <code>UPDATE</code> : (1) la clause<br/>
<code>WHERE</code> sélectionne les lignes affectées ; (2)<br/>
la clause <code>SET</code> indique comment modifier ces<br/>
lignes ; (3) le SGBD applique la modification<br/>
atomiquement (toutes les lignes en une seule<br/>
opération). Sans <code>WHERE</code>, <strong>toutes</strong> les lignes<br/>
sont modifiées, ce qui est rarement souhaité<br/>
et souvent catastrophique.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Bob est supprimé de la table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>UPDATE</code> ne supprime jamais de<br/>
ligne, il ne fait que modifier des<br/>
valeurs. Pour supprimer une ligne, il<br/>
faudrait utiliser <code>DELETE FROM comptes<br/>
WHERE solde &lt; 1000;</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Toutes les lignes voient leur solde<br/>
multiplié par $1{,}05$</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est ce qui se passerait si la<br/>
clause <code>WHERE</code> était absente. Avec<br/>
<code>WHERE solde &gt;= 1000</code>, seules les lignes<br/>
satisfaisant la condition sont<br/>
modifiées. Bob ($500$) ne fait pas partie<br/>
du lot.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Alice : $1050$, Bob : $500$ (inchangé),<br/>
Chloé : $2100$</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la clause <code>WHERE solde &gt;= 1000</code><br/>
sélectionne les lignes où le solde est<br/>
d'au moins $1000$ (Alice et Chloé). Pour<br/>
chacune, on applique <code>solde = solde * 1.05</code>.<br/>
Alice passe de $1000$ à $1050$, Chloé de<br/>
$2000$ à $2100$. Bob, dont le solde est<br/>
inférieur à $1000$, n'est pas affecté.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>La table reste inchangée car la clause<br/>
<code>WHERE</code> est trop restrictive</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Alice ($1000$) et Chloé ($2000$)<br/>
satisfont bien la condition <code>solde &gt;= 1000</code>,<br/>
donc leurs lignes sont modifiées. La<br/>
condition n'est pas trop restrictive : elle<br/>
est ciblée.</p>]]></text>
    </feedback>
  </answer>
</question>

</quiz>
