diff --git a/COURS/PLSQL-sol.tex b/COURS/PLSQL-sol.tex new file mode 100644 index 0000000..534c6d2 --- /dev/null +++ b/COURS/PLSQL-sol.tex @@ -0,0 +1,1544 @@ +\documentclass[a4paper,11pt]{article} +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{lastpage} +\usepackage{tikz,pgflibraryarrows,pgffor,pgflibrarysnakes} +\usetikzlibrary{decorations.pathreplacing} +\usepackage{url} +\usepackage{comment} +\usepackage{amsmath} +\usepackage{amsthm} + +\usepackage{eurosym} + + + +\theoremstyle{definition} +\newtheorem{exemple}{Exemple}[section] +\newtheorem{exercice}{Exercice} +\newtheorem{remarque}{Remarque}[section] +\newtheorem{definition}{Définition}[section] + +\usepackage{makeidx} +\usepackage[columnsep=9pt]{idxlayout} + +\usepackage{fancyvrb} + +%\makeindex +\selectlanguage{french} + +\usepackage[font=small,labelfont=bf,justification=centering]{caption} +\captionsetup[table]{name=Tableau} + +\usepackage{latexsym} +\usepackage{amsfonts} +\usepackage[normalem]{ulem} +\usepackage{array} +\usepackage{amssymb} +\usepackage{graphicx} + +\usepackage{subfig} +\usepackage{wrapfig} +\usepackage{wasysym} +\usepackage{enumitem} +\usepackage{adjustbox} +\usepackage{longtable} +\usepackage{changepage} +\usepackage{setspace} +\usepackage{hhline} +\usepackage{multicol} +\usepackage{float} +\usepackage{multirow} +\usepackage{slashbox} + +\usepackage{color, colortbl} +\definecolor{Gray}{gray}{0.9} + +\usepackage{fancyvrb} +\usepackage{fancyhdr}% fancy header +\usepackage{varwidth} +\usepackage{alltt} + + + \fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + + +\newcommand{\plsql}{PL/SQL} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries\leftmark} + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + + \pagestyle{monstyle} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1.5}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +\cachefalse % version prof +%\cachetrue % version etudiant + + \makeindex + + \begin{document} + + + +\begin{titlepage} +\begin{center} + +\textsc{\Large IUT Informatique Aubière \hfill 2018 - 2019} \\[.5cm] + +\hrule + +\ \\[.5cm] + +\vfill + +\textsc{\LARGE Bases de données} + +\vfill + +\textsc{\LARGE \plsql{}} + +\vfill + +{\Large Pascale \textsc{Brigoulet}, Franck \textsc{Glaziou}, } + +{\Large Pascal \textsc{Lafourcade} et Marie-Fran\c{c}oise + \textsc{Servajean}} + + +\vfill + + +\begin{tikzpicture} + +%%% un triangle + +%% horizonatale +\draw[blue,line width=1pt] (-1,0) -- (1,0); +\draw[blue,line width=1pt] (-2.5,-.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (-1.5,-1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (0,3.5) -- (1,3.5); + +%% Croissante +\draw[blue,line width=1pt] (0,0) -- (1,1.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (0,3.5); +\draw[blue,line width=1pt] (-1,0) -- (1,3.5); +\draw[blue,line width=1pt] (3,-1.75) -- (3.5,-0.75); + +%% Decroissante +\draw[blue,line width=1pt] (0.5,.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (1,1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (1,3.5) -- (3.5,-0.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (-1.5,-1.75); + + + +\end{tikzpicture} + +%% \begin{tikzpicture} + +%% %%% un cube + +%% \draw[red,line width=1pt] (0,.5) -- (1,0); +%% \draw[red,line width=1pt] (2,.5) -- (1,0); + +%% \draw[red,line width=1pt] (0,1.5) -- (1,1); +%% %\draw[red,line width=1pt] (0,1.5) -- (1,2); +%% \draw[red,line width=1pt] (0,1.5) -- (.5,1.75); +%% %\draw[red,line width=1pt] (2,1.5) -- (1,2); +%% \draw[red,line width=1pt] (2,1.5) -- (1.5,1.75); +%% \draw[red,line width=1pt] (2,1.5) -- (1,1); + +%% \draw[red,line width=1pt] (1,1) -- (1,0); +%% \draw[red,line width=1pt] (0,1.5) -- (0,.5); +%% \draw[red,line width=1pt] (2,1.5) -- (2,.5); + +%% %% droite + +%% %\draw[red,line width=1pt] (1.5,1.25) -- (2.5,0.75); +%% \draw[red,line width=1pt] (2,1) -- (2.5,0.75); +%% \draw[red,line width=1pt] (3.5,1.25) -- (2.5,0.75); + +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,1.75); +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,1.75); + +%% \draw[red,line width=1pt] (2.5,1.75) -- (2.5,.75); +%% %\draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.25); +%% \draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (3.5,1.25); + +%% %% Haut +%% \draw[red,line width=1pt] (0,2) -- (1,1.5); +%% %\draw[red,line width=1pt] (2,2) -- (1,1.5); +%% \draw[red,line width=1pt] (1.5,1.75) -- (1,1.5); + +%% \draw[red,line width=1pt] (0,3) -- (1,2.5); +%% \draw[red,line width=1pt] (0,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,2.5); + +%% \draw[red,line width=1pt] (1,2.5) -- (1,1.5); +%% \draw[red,line width=1pt] (0,3) -- (0,2); +%% %\draw[red,line width=1pt] (2,3) -- (2,2); +%% \draw[red,line width=1pt] (2,3) -- (2,2.5); + + +%% \end{tikzpicture} + +\vfill + + +\includegraphics[width=5cm]{iut-uca.png} +\end{center} + +\vfill + +{\Large Nom : \\ + +Prénom : \\ + +Groupe : \\ +} +%\url{http://mocodo.wingi.net/} + +%\url{http://mirror.hmc.edu/ctan/graphics/pgf/contrib/tkz-orm/tkz-orm.pdf} + + + +\end{titlepage} + +%% \section*{Avant Propos} + +%% L’objectif de ce cours de base de données avancées est de +%% présenter + + TD 1 : → Exo3 + TD 2 : Exo 3, 5, 6 7 + TD 3 : Reste + TD 4 : Partiel + +%% \newpage + +\tableofcontents + +\newpage + +\begin{center} +\LARGE {\bf \plsql{}} +\end{center} + +PL/SQL (Procedural Language / Structured Query Language) est un +langage fondé sur les paradigmes de programmation procédurale et +structurée. C'est un langage propriétaire, créé par Oracle et utilisé +dans le cadre de bases de données relationnelles. Il permet de +combiner des requêtes SQL et des instructions procédurales (boucles, +conditions...), dans le but de créer des traitements complexes +destinés à être stockés sur le serveur de base de données (objets +serveur), comme des procédures stockées ou des déclencheurs. + +\section{Fichier de commandes SQL/PLUS} + +SQL/Plus est un utilitaire en ligne de commande d'Oracle qui permet +aux utilisateurs d'exécuter interactivement des commandes SQL et +PL/SQL. Il est ainsi possible de paramètrer les fichiers de commandes +SQL. Pour cela il est important de stocker des informations dans des +variable : \code{variable vnoproduit CHAR(6)}. Cette commande déclare +une «bind variable» utilisable dans une commande SQL. Les diff\'eretns +formats autorisés sont : \code{NUMBER}, \code{CHAR(n)} et +\code{VARCHAR2(n)}. Afin d'interagir avec l'utilisateur il faut +pouvoir il existe deux commandes : + +\code{PROMPT taper le N° du produit} + +Cette commande affiche le texte placé après prompt (pas de quote) + +\code{ACCEPT vnoproduit} + +Cette commande permet la saisie d'une variable au clavier (la déclare +si elle ne l’était pas). + +\code{SELECT * FROM tproduit WHERE N°produit = ‘\&vnoproduit’;} + +\&{vnoproduit} permet d'acc\'eder \`a la chaîne de caractères +stock\'ee dans \code{vnoproduit}. + +\code{PRINT vnoproduit} + +Cette commande affiche la variable. + + + +\section{Exécution du code PL/SQL} + + +En SQL, les commandes sont transmises les unes après les autres et +traitées séparément par le moteur SQL, comme le montre la +Figure~\ref{fig:plsql1}. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{plsql2.png} +\end{center} +\caption{}\label{fig:plsql1} +\end{figure} + + +En extension procédurale de SQL (\plsql{}), les blocs de commandes +sont transmis globalement au moteur SQL, comme le montre la +Figure~\ref{fig:plsql2}. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{plsql1.png} +\end{center} +\caption{Interaction entre PL/SQL et SQL.}\label{fig:plsql2} +\end{figure} + + +\section{Exemple de programme \plsql{}} + +Le fichier de commandes ci-dessous permet la saisie de la référence +d’un produit et l’affichage de sa désignation ou d’un  message +d’erreur si le N° de produit n’existe pas. + +\begin{verbatim} +set echo off +set verify off +set feed off + +variable vnoproduit char(4) +variable vdesignation varchar2(30) +prompt taper la référence du produit à rechercher : +accept vnoproduit +\end{verbatim} +\begin{SaveVerbatim}{VerbEnv} +declare +dnoproduit char(4); + +begin +dnoproduit := ‘&vnoproduit’; +select designation into :vdesignation +from tproduit where noproduit = dnoproduit; + +exception +when no_data_found then + :vdesignation := ‘référence inconnue’; +end; +\end{SaveVerbatim} + \fbox{\BUseVerbatim{VerbEnv}} +\begin{verbatim} +. +/ +print vdesignation + +set verify on +set feed on +set echo on +\end{verbatim} + +\begin{remarque} + Ce fichier comporte trois parties : + \begin{itemize} + \item des commandes SQL+ pour la saisie de la référence produit, + \item un bloc \plsql{} pour accéder à la base, + \item des commandes SQL+ pour afficher le résultat. + \end{itemize} +\end{remarque} + +\plsql{} ne comprend pas d’instruction de saisie ou d’affichage. Les +commandes \code{SET} positionnent des variables d’environnement pour +éviter que le système n’affiche des informations « polluant » le +résultat : +\begin{itemize} +\item \code{set echo off} évite que le système n’affiche la commande + du bloc PL/SQL au moment où il l’exécute, +\item \code{set verify off} évite que le système n’affiche l’opération + de substitution au moment où il la fait, +\item \code{set feed off} évite que le système n’affiche le nombre de + lignes sélectionnées, +\item \code{.} le point indique la fin du mode PL/SQL, +\item \code{/} (seul sur une ligne) déclenche l’exécution du bloc PL/SQL ou de l’ ordre SQL stocké dans le buffer. +\end{itemize} + +\section{Structure d'un bloc \plsql{}} + +\plsql{} n'interprète pas une commande, mais un ensemble de commandes +contenu dans un "bloc" \plsql{}. Un bloc est composé de trois +sections. +\begin{itemize} +\item Les sections \code{DECLARE} et \code{EXCEPTION} sont facultatives. +\item Chaque instruction, de n'importe quelle section, est terminée + par un \code{;} +\item Possibilité de placer des commentaires : \code{/* commentaire + sur plusieurs lignes commençant par au moins un espace */} +\end{itemize} + +Attention aux points virgules: en cas d’oubli, Oracle affiche un N° de +ligne attendant la suite de commande SQL. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{bloc.png} +\end{center} +\caption{Structure d'un programme \plsql{}.}\label{fig:bloc} +\end{figure} + +\section{Types de variables utilisés en \plsql{}} + +Variables locales déclarées dans \code{DECLARE} et il est important de +mettre le type adapt\'e en suivant la syntaxe suivante : + + \verb+nom_variable type := valeur;+ + +Les diff\'erents types possibles sont : \code{CHAR, NUMBER, DATE, + VARCHAR2}. + +Il est n\'ecessaire de choisir le type \`a l'initialisation lors de la +déclaration et aussi sa valeur intiale comme le montre les deux +exemples suivants : +\begin{itemize} +\item \code{NB NUMBER := 1;} +\item \verb+nom_variable nomtable.nomcol %type+ +\end{itemize} + +\begin{exemple} Cr\'eation de variable. + +\code{dnoprod tproduit.noproduit \%type;} + +\code{ddesignation tproduit.designation \%type ;} +\end{exemple} + +Il est possible de cr\'eer des tableaux en \plsql{}. % +%% Variables de l'environnement extérieur à \plsql{}: +%% \begin{itemize} +%% \item champs d'écran en SQL*Forms, +%% \item variables définies en langage hôte dans PRO*. Les variables de +%% l’environnement sont toujours préfixées. +%\item + Les variables définies dans SQL*Plus par \code{VARIABLE} ou +\code{ACCEPT} sont préfixées de : pour affectation, de "\verb+&+" pour +substitution. + +% \end{itemize} + +\begin{exemple} Exemple simple d'utilisation de variable. +\begin{verbatim} +dnoproduit := '&vnoproduit'; +select designation into :vdesignation +from tproduit +where noproduit = '&vnoproduit'; + +select designation into ddesignation +from tproduit +where noproduit = dnoproduit; +\end{verbatim} + +Tableaux PL/SQL. + +Déclaration : + +\begin{verbatim} +DECLARE +... +TYPE tchar4 IS TABLE OF CHAR(4) +INDEX BY BINARY_INTEGER ; +table_noprod tchar4 ; +p BINARY_INTEGER ; +\end{verbatim} + +Utilisation : + +\begin{verbatim} +BEGIN +... +p := 1 ; +table_noprod(p) := ‘p001’ ; +\end{verbatim} +\end{exemple} + +\section{Les traitements du bloc \code{BEGIN}} +\subsection{L'ordre SELECT :} +\begin{itemize} +\item Syntaxe : + \begin{verbatim} + SELECT coll, col2 + INTO var1, var2 + FROM table + [WHERE condition]; +\end{verbatim} + \item + Règle : + \begin{itemize} + \item La clause \code{INTO} est {\bf obligatoire}. + \item Le \code{SELECT} doit obligatoirement ramener une ligne + et une seule, sinon erreur. Pour traiter un ordre + \code{SELECT} qui pourrait ramener plusieurs lignes, il faut + utiliser un curseur. + \end{itemize} +\end{itemize} + Les autres ordres de manipulation sont inchangés; des + variables peuvent être utilisées : +\begin{verbatim} +INSERT INTO table VALUES( var1, ‘chaine’, 123, var2); +UPDATE table SET col2 = var1 WHERE col1 = var2; +\end{verbatim} + +\begin{exercice} + Nombre de fournisseurs d’un produit donné : le résultat sera écrit + dans une table \code{ligne}. Les tables utilis\'ees sont donn\'ees + dans la Figure~\ref{fig:bd}. +\end{exercice} + +\begin{verbatim} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)); + +set echo off ; +set verify off ; +set feed off ; +variable vnoproduit char(4) +prompt Entre le numero du produit: +accept vnoproduit + +DECLARE + +dnbfournisseur number ; + +BEGIN + +SELECT count(*) into dnbfournisseur +FROM Tproduitfourn +WHERE noprod ='& vnoproduit'; + +INSERT INTO tligne VALUES ('NB fournisseur='||to_char(dnbfournisseur)| +|' du produit '|| '&vnoproduit'); + +END; +. +/ + +SELECT * FROM tligne ; + +set verify on ; +set feed on ; +set echo on ; +\end{verbatim} + + + +\subsection{Traitements conditionnels \code{IF...THEN...END IF;}} +\begin{verbatim} + IF condition1 THEN traitement1; + ELSE traitement2; + END IF; +\end{verbatim} + +Les opérateurs utilisés dans les conditions sont les même que dans SQL +: + +\verb+ =, <, >, !=, >=, <=, IS NULL, IS NOT NULL, BETWEEN, LIKE, AND, OR, ...+ + + +\begin{exercice} +Nombre de fournisseurs d’un produit donné : s’il n’y a pas de +fournisseur, compter le nombre de produits : il doit être 1 ou +0. \'Ecrire dans une table de lignes soit le nombre de fournisseurs +soit le message ‘\code{le produit n’existe pas}’. +\end{exercice} +\begin{verbatim} +DROP TABLE tligne; +CREATE TABLE tligne (ligne varchar2(100)); + +set echo off; +set verify off; +set feed off; + +variable vnoproduit char(4) +prompt Entre le numero du produit: +accept vnoproduit + +DECLARE + +dnbfournisseur number; +dnbproduit number; + +BEGIN + +SELECT count(*) into dnbfournisseur +FROM Tproduitfourn +WHERE noprod ='& vnoproduit'; + +IF dnbfournisseur = THEN + +SELECT count(noproduit) into dnbproduit +FROM Tproduit +WHERE noproduit = & vnoproduit'; + +if dnbproduit = 0 then +INSERT INTO tligne VALUES ('Le produit ' || '&vnoproduit'|| ' n''existe pas'); +else +INSERT INTO tligne VALUES ('NB fournisseur='||to_char(dnbfournisseur)| +|' du produit ' || '&vnoproduit'); +end if; +END IF; +END; +. +/ + +SELECT * FROM tligne; + +set verify on; +set feed on; +set echo on; +\end{verbatim} + +\subsection{Traitements répétitifs \code{WHILE ...LOOP ...END LOOP;}} + + La boucle \code{WHILE}: L'exécution de la boucle se fait tant + que la condition de la clause de \code{WHILE} est vérifiée. +\begin{verbatim} + BEGIN + WHILE condition + LOOP + instructions; + END LOOP; + END; +\end{verbatim} +La condition est une combinaison d'expressions au moyen d'opérateurs : +\verb+<, >, =, !=, AND, OR, LIKE, ...+ + +\begin{exemple}Calcul de factorielle. +\begin{verbatim} +CREATE TABLE tligne (ligne VARCHAR2(200)); +VARIABLE n NUMBER +PROMPT taper n +ACCEPT n + +DECLARE +fn NUMBER := 1; +i NUMBER :=1; +n NUMBER :='&n'; +BEGIN + WHILE i1000 + then UPDATE Tproduit SET prixv=dprix*1.1 WHERE CURRENT of r; COMMIT; + else UPDATE Tproduit SET prixv=dprix*1.05 WHERE CURRENT of r; COMMIT; + end if; + FETCH r INTO dprixv; + END LOOP; +CLOSE R; + +END; +. +/ + +set verify on; +set feed on; +set echo on; +\end{verbatim} + +Erreur utilisateur : \code{EXCEPTION, RAISE} + +Le traitement de l’anomalie doit être déclenché en passant dans la +partie \code{EXCEPTION} par \code{RAISE}. +\begin{verbatim} +DECLARE +... +nom_erreur EXCEPTION; +... +BEGIN +... +IF anomalie +THEN RAISE nom_erreur; +... +EXCEPTION +WHEN nom_erreur THEN +traitement à effectuer en cas d’anomalie; +END ; +\end{verbatim} + +Sortie du bloc après exécution du traitement. + +\begin{exemple} +Accèder au stock d’un produit de Numéro donné. Erreur Oracle quand le +produit n’existe pas Erreur utilisateur quand le stock est nul Les +anomalies sont placées dans une table \code{terreur(z1 varchar2(30), + z2 varchar2(30))} + +\begin{verbatim} +DECLARE +... +stock_nul EXCEPTION; +dstock number; +... +BEGIN +SELECT stock INTO dstock FROM tproduit WHERE noproduit = ‘&vnoproduit’; +IF stock = 0 +THEN RAISE stock_nul; +traitement quand le stock n’est pas nul... +EXCEPTION +WHEN NO_DATA_FOUND THEN +INSERT INTO terreur VALUES (‘&vnoproduit’, ‘produit inconnu’); +WHEN stock_nul THEN +INSERT INTO terreur VALUES (‘&vnoproduit’, ‘stock nul’); +END; +\end{verbatim} +\end{exemple} + +\begin{exercice} Pour remplacer l’erreur Oracle par une erreur utilisateur, compter le nombre de produits ayant le numéro donné et déclencher une exception si ce nombre est nul. +\end{exercice} + +\begin{verbatim} +DROP TABLE tligne; +CREATE TABLE tligne (ligne varchar2(100)); + +set echo off; +set verify off; +set feed off; + +variable vnoproduit varchar2(4) + +prompt Entrer le numereo du produit: +accept vnoproduit + +DECLARE +nbproduitnull EXCEPTION; +dnbproduit number; + +BEGIN + +SELECT count(*) INTO dnbproduit +FROM Tproduit +WHERE noproduit ='&vnoproduit' + +if dnobproduit =0 the raise nbproduitnull; +end if; + +EXCEPTION + when nbproduitnull then + INSERT INTO tligne VLAUES ('&vnoporduit)'||'n existe pas'); +. +/ +SELECT * FROM tligne; +set verify on; +set feed on; +set echo on; +\end{verbatim} + + +\newpage + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=18cm]{BD.png} +\end{center} +\caption{Base de donn\'ees pour les exercices.}\label{fig:bd} +\end{figure} + +\newpage + +\begin{center} + {\bf Commandes utiles pour les TP} +\end{center} + +\paragraph{Premi\`ere s\'eance :} Connexion : \verb+sqlplus /@KIROV+ + +\verb+source /etc/profile+ + +Lancer \verb+sqlplus+ avec cette commande \verb+rlwrap sqlplus+ vous +permet d'avoir l'historique. + + +Lors de votre première connexion modifier votre mot de passe avec la +commande SQL : \verb+PASSWORD;+ + +Ce qui est équivalent à : +\verb+ALTER USER dupond IDENTIFIED BY password;+ + +Si vous avez perdu votre mot de passe se connecter en \code{ssh} sur +\code{londres} et faire \code{oracle\_passwd} + + +Pour lancer un fichier \verb+.sql+ en sqlplus, il suffit de taper : +\verb+@toto.sql;+ + +Pour quitter sqlplus, il suffit de taper : \verb+quit;+ + + +\paragraph{Mise en forme : } + +Sous sqlplus : +\begin{verbatim} +Set linesize 150 -- positionne la taille d'une ligne +Set pagesize 300 -- positionne le nombre de lignes avant de réafficher les entêtes +Set pages 0 -- n'affiche pas les entêtes +Col for A10 -- défini que la colonne nom_colonne va être affiché sur +10 caractères alphanumériques, 999.99 pour les valeurs numériques. +\end{verbatim} + + +\paragraph{Corbeille :} Vider les tables \verb+BIN$$xxxx+ : +\verb+PURGE RECYCLEBIN;+ + + +\paragraph{D\'ebug :} Connaître l'utilisateur connect\'e : \verb+show user;+ + +Liste des tables d'un \verb+user+ : \verb+SELECT table_name FROM user_tables;+ + +Lister les tables accessibles par l'utilisateur +:\verb+ SELECT table_name FROM all_tables;+ + +Lister toutes les tables possédées par un utilisateur +\verb+SELECT * FROM all_tables WHERE owner='PALAFOUR';+ + +Liste des vues d'un user : \verb+SELECT view_name FROM user_views;+ + +Liste des contraintes : \verb+SELECT * FROM user_constraints WHERE table_name=’’;+ + +\verb+SELECT * FROM user_cons_columns WHERE table_name='
";+ + + +\paragraph{Contraintes :} Description d'une table : \verb+describe
+ ou +\verb+desc
+ + +Liste des colonnes concernées par les contraintes : +\verb+SELECT * FROM user_cons_columns;+ + +Lire une table d'un autre schéma : + +\verb+SELECT * FROM .; -- ou schma = login de connexion de l'utilisateur+ + +\paragraph{Affichage :} ~ \\ + +\verb+SET HEADING OFF+ + +\verb+SET FEEDBACK OFF+ + +\paragraph{Acc\`es fichiers} +\begin{verbatim} +https://homeweb.iut-clermont.uca.fr/pydio/ +\end{verbatim} + +\paragraph{Aide en ligne} +\begin{verbatim} +http://cr2i.intranet.iut.local/site/ +\end{verbatim} + + %\newpage + +%\printindex + \end{document} diff --git a/COURS/PLSQL.tex b/COURS/PLSQL.tex new file mode 100644 index 0000000..47c455a --- /dev/null +++ b/COURS/PLSQL.tex @@ -0,0 +1,1028 @@ +\documentclass[a4paper,11pt]{article} +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{lastpage} +\usepackage{tikz,pgflibraryarrows,pgffor,pgflibrarysnakes} +\usetikzlibrary{decorations.pathreplacing} +\usepackage{url} +\usepackage{comment} +\usepackage{amsmath} +\usepackage{amsthm} + +\usepackage{eurosym} + + + +\theoremstyle{definition} +\newtheorem{exemple}{Exemple}[section] +\newtheorem{exercice}{Exercice} +\newtheorem{remarque}{Remarque}[section] +\newtheorem{definition}{Définition}[section] + +\usepackage{makeidx} +\usepackage[columnsep=9pt]{idxlayout} + +\usepackage{fancyvrb} + +%\makeindex +\selectlanguage{french} + +\usepackage[font=small,labelfont=bf,justification=centering]{caption} +\captionsetup[table]{name=Tableau} + +\usepackage{latexsym} +\usepackage{amsfonts} +\usepackage[normalem]{ulem} +\usepackage{array} +\usepackage{amssymb} +\usepackage{graphicx} + +\usepackage{subfig} +\usepackage{wrapfig} +\usepackage{wasysym} +\usepackage{enumitem} +\usepackage{adjustbox} +\usepackage{longtable} +\usepackage{changepage} +\usepackage{setspace} +\usepackage{hhline} +\usepackage{multicol} +\usepackage{float} +\usepackage{multirow} +\usepackage{slashbox} + +\usepackage{color, colortbl} +\definecolor{Gray}{gray}{0.9} + +\usepackage{fancyvrb} +\usepackage{fancyhdr}% fancy header +\usepackage{varwidth} +\usepackage{alltt} + + + \fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + + +\newcommand{\plsql}{PL/SQL} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries\leftmark} + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + + \pagestyle{monstyle} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1.5}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +\cachefalse % version prof +%\cachetrue % version etudiant + + \makeindex + + \begin{document} + + + +\begin{titlepage} +\begin{center} + +\textsc{\Large IUT Informatique Aubière \hfill 2019 - 2020} \\[.5cm] + +\hrule + +\ \\[.5cm] + +\vfill + +\textsc{\LARGE Bases de données} + +\vfill + +\textsc{\LARGE \plsql{}} + +\vfill + +{\Large Pascale \textsc{Brigoulet}, Franck \textsc{Glaziou}, } + +{\Large Pascal \textsc{Lafourcade} et Marie-Fran\c{c}oise + \textsc{Servajean}} + + +\vfill + + +\begin{tikzpicture} + +%%% un triangle + +%% horizonatale +\draw[blue,line width=1pt] (-1,0) -- (1,0); +\draw[blue,line width=1pt] (-2.5,-.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (-1.5,-1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (0,3.5) -- (1,3.5); + +%% Croissante +\draw[blue,line width=1pt] (0,0) -- (1,1.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (0,3.5); +\draw[blue,line width=1pt] (-1,0) -- (1,3.5); +\draw[blue,line width=1pt] (3,-1.75) -- (3.5,-0.75); + +%% Decroissante +\draw[blue,line width=1pt] (0.5,.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (1,1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (1,3.5) -- (3.5,-0.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (-1.5,-1.75); + + + +\end{tikzpicture} + +%% \begin{tikzpicture} + +%% %%% un cube + +%% \draw[red,line width=1pt] (0,.5) -- (1,0); +%% \draw[red,line width=1pt] (2,.5) -- (1,0); + +%% \draw[red,line width=1pt] (0,1.5) -- (1,1); +%% %\draw[red,line width=1pt] (0,1.5) -- (1,2); +%% \draw[red,line width=1pt] (0,1.5) -- (.5,1.75); +%% %\draw[red,line width=1pt] (2,1.5) -- (1,2); +%% \draw[red,line width=1pt] (2,1.5) -- (1.5,1.75); +%% \draw[red,line width=1pt] (2,1.5) -- (1,1); + +%% \draw[red,line width=1pt] (1,1) -- (1,0); +%% \draw[red,line width=1pt] (0,1.5) -- (0,.5); +%% \draw[red,line width=1pt] (2,1.5) -- (2,.5); + +%% %% droite + +%% %\draw[red,line width=1pt] (1.5,1.25) -- (2.5,0.75); +%% \draw[red,line width=1pt] (2,1) -- (2.5,0.75); +%% \draw[red,line width=1pt] (3.5,1.25) -- (2.5,0.75); + +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,1.75); +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,1.75); + +%% \draw[red,line width=1pt] (2.5,1.75) -- (2.5,.75); +%% %\draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.25); +%% \draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (3.5,1.25); + +%% %% Haut +%% \draw[red,line width=1pt] (0,2) -- (1,1.5); +%% %\draw[red,line width=1pt] (2,2) -- (1,1.5); +%% \draw[red,line width=1pt] (1.5,1.75) -- (1,1.5); + +%% \draw[red,line width=1pt] (0,3) -- (1,2.5); +%% \draw[red,line width=1pt] (0,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,2.5); + +%% \draw[red,line width=1pt] (1,2.5) -- (1,1.5); +%% \draw[red,line width=1pt] (0,3) -- (0,2); +%% %\draw[red,line width=1pt] (2,3) -- (2,2); +%% \draw[red,line width=1pt] (2,3) -- (2,2.5); + + +%% \end{tikzpicture} + +\vfill + + +\includegraphics[width=5cm]{iut-uca.png} +\end{center} + +\vfill + +{\Large Nom : \\ + +Prénom : \\ + +Groupe : \\ +} +%\url{http://mocodo.wingi.net/} + +%\url{http://mirror.hmc.edu/ctan/graphics/pgf/contrib/tkz-orm/tkz-orm.pdf} + + + +\end{titlepage} + +%% \section*{Avant Propos} + +%% L’objectif de ce cours de base de données avancées est de +%% présenter + +%% TD 1 : → Exo3 +%% TD 2 : Exo 3, 5, 6 7 +%% TD 3 : Reste +%% TD 4 : Partiel + +%% \newpage + +\tableofcontents + +\newpage + +\begin{center} +\LARGE {\bf \plsql{}} +\end{center} + +PL/SQL (Procedural Language / Structured Query Language) est un +langage fondé sur les paradigmes de programmation procédurale et +structurée. C'est un langage propriétaire, créé par Oracle et utilisé +dans le cadre de bases de données relationnelles. Il permet de +combiner des requêtes SQL et des instructions procédurales (boucles, +conditions...), dans le but de créer des traitements complexes +destinés à être stockés sur le serveur de base de données (objets +serveur), comme des procédures stockées ou des déclencheurs. + +\section{Fichier de commandes SQL/PLUS} + +SQL/Plus est un utilitaire en ligne de commande d'Oracle qui permet +aux utilisateurs d'exécuter interactivement des commandes SQL et +PL/SQL. Il est ainsi possible de paramètrer les fichiers de commandes +SQL. Pour cela il est important de stocker des informations dans des +variable : \code{variable vnoproduit CHAR(6)}. Cette commande déclare +une «bind variable» utilisable dans une commande SQL. Les diff\'erents +formats autorisés sont : \code{NUMBER}, \code{CHAR(n)} et +\code{VARCHAR2(n)}. Afin d'interagir avec l'utilisateur il existe deux +commandes : + +\code{PROMPT taper le N° du produit} + +Cette commande affiche le texte placé après prompt. Attnetion il n'y a +pas de quote. + +\code{ACCEPT vnoproduit} + +Cette commande permet la saisie d'une variable au clavier et la +déclare si elle ne l’était pas. + +\code{SELECT * FROM tproduit WHERE N°produit = ‘\&vnoproduit’;} + +\code{\&vnoproduit} permet d'acc\'eder \`a la chaîne de caractères +stock\'ee dans la variable \code{vnoproduit}. + +\code{PRINT vnoproduit} + +Cette commande affiche le contenu de la variable. + + + +\section{Exécution du code PL/SQL} + + +En SQL, les commandes sont transmises les unes après les autres et +traitées séparément par le moteur SQL, comme le montre la +Figure~\ref{fig:plsql1}. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{plsql2.png} +\end{center} +\caption{}\label{fig:plsql1} +\end{figure} + + +En extension procédurale de SQL (\plsql{}), les blocs de commandes +sont transmis globalement au moteur SQL, comme le montre la +Figure~\ref{fig:plsql2}. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{plsql1.png} +\end{center} +\caption{Interaction entre PL/SQL et SQL.}\label{fig:plsql2} +\end{figure} + + +\section{Exemple de programme \plsql{}} + +Le fichier de commandes ci-dessous permet la saisie de la référence +d’un produit et l’affichage de sa désignation ou d’un  message +d’erreur si le N° de produit n’existe pas. + +\begin{verbatim} +set echo off +set verify off +set feed off + +variable vnoproduit char(4) +variable vdesignation varchar2(30) +prompt taper la référence du produit à rechercher : +accept vnoproduit +\end{verbatim} +\begin{SaveVerbatim}{VerbEnv} +declare +dnoproduit char(4); + +begin +dnoproduit := ‘&vnoproduit’; +select designation into :vdesignation +from tproduit where noproduit = dnoproduit; + +exception +when no_data_found then + :vdesignation := ‘référence inconnue’; +end; +\end{SaveVerbatim} + \fbox{\BUseVerbatim{VerbEnv}} +\begin{verbatim} +. +/ +print vdesignation + +set verify on +set feed on +set echo on +\end{verbatim} + +\begin{remarque} + Ce fichier comporte trois parties : + \begin{itemize} + \item des commandes SQL+ pour la saisie de la référence produit, + \item un bloc \plsql{} pour accéder à la base, + \item des commandes SQL+ pour afficher le résultat. + \end{itemize} +\end{remarque} + +\plsql{} ne comprend pas d’instruction de saisie ou d’affichage. Les +commandes \code{SET} positionnent des variables d’environnement pour +éviter que le système n’affiche des informations « polluant » le +résultat : +\begin{itemize} +\item \code{set echo off} évite que le système n’affiche la commande + du bloc PL/SQL au moment où il l’exécute, +\item \code{set verify off} évite que le système n’affiche l’opération + de substitution au moment où il la fait, +\item \code{set feed off} évite que le système n’affiche le nombre de + lignes sélectionnées, +\item \code{.} le point indique la fin du mode PL/SQL, +\item \code{/} (seul sur une ligne) déclenche l’exécution du bloc PL/SQL ou de l’ ordre SQL stocké dans le buffer. +\end{itemize} + +\section{Structure d'un bloc \plsql{}} + +\plsql{} n'interprète pas une commande, mais un ensemble de commandes +contenu dans un "bloc" \plsql{}. Un bloc est composé de trois +sections. +\begin{itemize} +\item Les sections \code{DECLARE} et \code{EXCEPTION} sont facultatives. +\item Chaque instruction, de n'importe quelle section, est terminée + par un \code{;} +\item Possibilité de placer des commentaires : \code{/* commentaire + sur plusieurs lignes commençant par au moins un espace */} +\end{itemize} + +Attention aux points virgules: en cas d’oubli, Oracle affiche un N° de +ligne attendant la suite de commande SQL. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{bloc.png} +\end{center} +\caption{Structure d'un programme \plsql{}.}\label{fig:bloc} +\end{figure} + +\section{Types de variables utilisés en \plsql{}} + +Variables locales déclarées dans \code{DECLARE} et il est important de +mettre le type adapt\'e en suivant la syntaxe suivante : + + \verb+nom_variable type := valeur;+ + +Les diff\'erents types possibles sont : \code{CHAR, NUMBER, DATE, + VARCHAR2}. + +Il est n\'ecessaire de choisir le type \`a l'initialisation lors de la +déclaration et aussi sa valeur intiale comme le montre les deux +exemples suivants : +\begin{itemize} +\item \code{NB NUMBER := 1;} +\item \verb+nom_variable nomtable.nomcol %type+ +\end{itemize} + +\begin{exemple} Cr\'eation de variable. + +\code{dnoprod tproduit.noproduit \%type;} + +\code{ddesignation tproduit.designation \%type ;} +\end{exemple} + +Il est possible de cr\'eer des tableaux en \plsql{}. % +%% Variables de l'environnement extérieur à \plsql{}: +%% \begin{itemize} +%% \item champs d'écran en SQL*Forms, +%% \item variables définies en langage hôte dans PRO*. Les variables de +%% l’environnement sont toujours préfixées. +%\item + Les variables définies dans SQL*Plus par \code{VARIABLE} ou +\code{ACCEPT} sont préfixées de : pour affectation, de "\verb+&+" pour +substitution. + +% \end{itemize} + +\begin{exemple} Exemple simple d'utilisation de variable. +\begin{verbatim} +dnoproduit := '&vnoproduit'; +select designation into :vdesignation +from tproduit +where noproduit = '&vnoproduit'; + +select designation into ddesignation +from tproduit +where noproduit = dnoproduit; +\end{verbatim} + +Tableaux PL/SQL. + +Déclaration : + +\begin{verbatim} +DECLARE +... +TYPE tchar4 IS TABLE OF CHAR(4) +INDEX BY BINARY_INTEGER ; +table_noprod tchar4 ; +p BINARY_INTEGER ; +\end{verbatim} + +Utilisation : + +\begin{verbatim} +BEGIN +... +p := 1 ; +table_noprod(p) := ‘p001’ ; +\end{verbatim} +\end{exemple} + +\section{Les traitements du bloc \code{BEGIN}} +\subsection{L'ordre SELECT :} +\begin{itemize} +\item Syntaxe : + \begin{verbatim} + SELECT coll, col2 + INTO var1, var2 + FROM table + [WHERE condition]; +\end{verbatim} + \item + Règle : + \begin{itemize} + \item La clause \code{INTO} est {\bf obligatoire}. + \item Le \code{SELECT} doit obligatoirement ramener une ligne + et une seule, sinon erreur. Pour traiter un ordre + \code{SELECT} qui pourrait ramener plusieurs lignes, il faut + utiliser un curseur. + \end{itemize} +\end{itemize} + Les autres ordres de manipulation sont inchangés; des + variables peuvent être utilisées : +\begin{verbatim} +INSERT INTO table VALUES(var1, ‘chaine’, 123, var2); +UPDATE table SET col2 = var1 WHERE col1 = var2; +\end{verbatim} + +\begin{exercice} + Nombre de fournisseurs d’un produit donné : le résultat sera écrit + dans une table \code{ligne}. Les tables utilis\'ees sont donn\'ees + dans la Figure~\ref{fig:bd}. +\end{exercice} + +\subsection{Traitements conditionnels \code{IF...THEN...END IF;}} +\begin{verbatim} + IF condition1 THEN traitement1; + ELSE traitement2; + END IF; +\end{verbatim} + +Les opérateurs utilisés dans les conditions sont les même que dans SQL +: + +\verb+ =, <, >, !=, >=, <=, IS NULL, IS NOT NULL, BETWEEN, LIKE, AND, OR, ...+ + + +\begin{exercice} +Nombre de fournisseurs d’un produit donné : s’il n’y a pas de +fournisseur, compter le nombre de produits : il doit être $\geq 1$ ou +0. \'Ecrire dans une table de lignes soit le nombre de fournisseurs +soit le message ‘\code{le produit n’existe pas}’. +\end{exercice} + +\subsection{Traitements répétitifs \code{WHILE ...LOOP ...END LOOP;}} + + La boucle \code{WHILE}: L'exécution de la boucle se fait tant + que la condition de la clause de \code{WHILE} est vérifiée. +\begin{verbatim} + BEGIN + WHILE condition + LOOP + instructions; + END LOOP; + END; +\end{verbatim} +La condition est une combinaison d'expressions au moyen d'opérateurs : +\verb+<, >, =, !=, AND, OR, LIKE, ...+ + +\begin{exemple}Calcul de factorielle. +\begin{verbatim} +CREATE TABLE tligne (ligne VARCHAR2(200)); +VARIABLE n NUMBER +PROMPT taper n +ACCEPT n + +DECLARE +fn NUMBER := 1; +i NUMBER :=1; +n NUMBER :='&n'; +BEGIN + WHILE i/@KIROV+ + +\verb+source /etc/profile+ + +Lancer \verb+sqlplus+ avec cette commande \verb+rlwrap sqlplus+ vous +permet d'avoir l'historique. + + +Lors de la première connexion modifier le mot de passe avec la +commande SQL : \verb+PASSWORD;+ + +Ce qui est équivalent à : +\verb+ALTER USER dupond IDENTIFIED BY password;+ + +Si le mot de passe est \'egar\'e quelque part, il faut se connecter en +\code{ssh} sur \code{londres} et faire \code{oracle\_passwd} + + +Pour lancer un fichier \verb+.sql+ en sqlplus, il suffit de taper : +\verb+@toto.sql;+ + +Pour quitter sqlplus, il suffit de taper : \verb+quit;+ + + +\paragraph{Mise en forme : } + +Sous SQL/PLUS : +\begin{verbatim} +Set linesize 150 -- positionne la taille d'une ligne +Set pagesize 300 -- positionne le nombre de lignes avant de réafficher les entêtes +Set pages 0 -- n'affiche pas les entêtes +Col for A10 -- défini que la colonne nom_colonne va être affiché sur 10 caractères +alphanumériques, 999.99 pour les valeurs numériques. +\end{verbatim} + + +\paragraph{Corbeille :} Vider les tables \verb+BIN$$xxxx+ : avec la +commande \verb+PURGE RECYCLEBIN;+ + + +\paragraph{D\'ebug :} Afficher la strucutre de la table \code{nba} : \verb+describle nba;+ + +Connaître l'utilisateur connect\'e : \verb+show user;+ + +Liste des tables d'un \verb+user+ : \verb+SELECT table_name FROM user_tables;+ + +Lister les tables accessibles par l'utilisateur +: \verb+ SELECT table_name FROM all_tables;+ + +Lister toutes les tables possédées par un utilisateur +\verb+SELECT * FROM all_tables WHERE owner='PALAFOUR';+ + +Liste des vues d'un \code{user} : \verb+SELECT view_name FROM user_views;+ + +Liste des contraintes : \verb+SELECT * FROM user_constraints WHERE table_name=’
’;+ + +\verb+SELECT * FROM user_cons_columns WHERE table_name='
";+ + +\verb+show errros+ affiche les erreurs des fonctions. + +\paragraph{Contraintes :} Description d'une table : \verb+describe
+ ou +\verb+desc
+; + +Liste des colonnes concernées par les contraintes : +\verb+SELECT * FROM user_cons_columns;+ + +Lire une table d'un autre schéma : + +\verb+SELECT * FROM .; -- ou schma = login de connexion de l'utilisateur+ + + + +\paragraph{Affichage :} +\verb+SET HEADING OFF+ + +\verb+SET FEEDBACK OFF+ + +\paragraph{Travailler \`a la maison} + +Il est possible d'acc\`eder par SSH \`a la machine +\texttt{londres}. L'adresse de la passerelle est +\texttt{ssh.iut-clermont.uca.fr} qui n'est accessible que par une +authentification avec des clefs SSH. + +Cet acc\`es vous permettra d'acc\`eder au serveur de base de donn\'ees +comme lorsque vous travailler \`a l'IUT. Avant de pouvoir se +connecter, il faut activer l'acc\`es \`a l'IUT sur +\texttt{http://erlin.iut.local} ce qui peut prendre 30 minutes. + +Pour d\'eposer vos clefs vous pouvez utiliser +\url{https://homeweb.iut-clermont.uca.fr} + +%.ssh/authorized_keys +%londres.iut.local +%SSH http://cr2i.intranet.iut.local/site/page/documentation/ssh/ + + +%% Faire du SQLPLUS depuis chez-vous en faisant du SSH en tapant cette +%% commande où vous devez remplacer LOGIN par votre login pour vous +%% connecter sur Linux à l'IUT: \verb+ssh LOGIN@193.49.118.206+ + +%% Le workflow le plus propre est d'avoir un fichier sur votre machine +%% personnelle que vous copier en faisant un \code{scp} sur la machine + +%% Par exemple la commande ci-dessous copie le fichier +%% creation-donnees.sql de mon ordintaeur sur la machine virtuelle + +%% \verb+scp creation-donnees.sql palafour@193.49.118.206:.+ + +%% Par contre une fois que je suis déconnecté de ma connexion ssh tous +%% les fichiers peuvent \^etre détruits car votre repertoire personnel +%% (home) sur ce serveur est TEMPORAIRE. Vos donnees peuvent etre +%% perdues a tout moment. Ne stocker RIEN ici. + + + +\paragraph{En cas de blocage :} + +Dans un terminal executer la commande suivante pour voir les \code{pid} +des processus zombies : \verb+ps -aux | grep sqlplus+ + +Ensuite tuer ces zombies gr\^ace \`a la commande \code{kill -9 numerodepid} + \newpage + %\newpage + +%\printindex + \end{document} diff --git a/COURS/ProC.tex b/COURS/ProC.tex new file mode 100644 index 0000000..180c2c7 --- /dev/null +++ b/COURS/ProC.tex @@ -0,0 +1,1309 @@ +\documentclass[a4paper,11pt]{article} +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{lastpage} +\usepackage{tikz,pgflibraryarrows,pgffor,pgflibrarysnakes} +\usetikzlibrary{decorations.pathreplacing} +\usepackage{url} +\usepackage{comment} +\usepackage{amsmath} +\usepackage{amsthm} + + + +\theoremstyle{definition} +\newtheorem{exemple}{Exemple}[section] +\newtheorem{exercice}{Exercice}[section] +\newtheorem{remarque}{Remarque}[section] +\newtheorem{definition}{Définition}[section] + +\usepackage{makeidx} +\usepackage[columnsep=9pt]{idxlayout} + +\usepackage{fancyvrb} + +%\makeindex +\selectlanguage{french} + +\usepackage[font=small,labelfont=bf,justification=centering]{caption} +\captionsetup[table]{name=Tableau} + +\usepackage{latexsym} +\usepackage{amsfonts} +\usepackage[normalem]{ulem} +\usepackage{array} +\usepackage{amssymb} +\usepackage{graphicx} + +\usepackage{subfig} +\usepackage{wrapfig} +\usepackage{wasysym} +\usepackage{enumitem} +\usepackage{adjustbox} +\usepackage{longtable} +\usepackage{changepage} +\usepackage{setspace} +\usepackage{hhline} +\usepackage{multicol} +\usepackage{float} +\usepackage{multirow} +\usepackage{slashbox} + +\usepackage{color, colortbl} +\definecolor{Gray}{gray}{0.9} + +\usepackage{fancyvrb} +\usepackage{fancyhdr}% fancy header +\usepackage{varwidth} +\usepackage{alltt} + + + \fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + + +\newcommand{\proc}{Pro$^{*}$C} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries\leftmark} + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + + \pagestyle{monstyle} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +%\cachefalse % version prof +\cachetrue % version etudiant + + \makeindex + + \begin{document} + + + +\begin{titlepage} +\begin{center} + +\textsc{\Large IUT Informatique Aubière \hfill 2019 - 2020} \\[.5cm] + +\hrule + +\ \\[.5cm] + +\vfill + +\textsc{\LARGE Bases de données} + +\vfill + +\textsc{\LARGE \proc{}} + +\vfill + +{\Large Pascale \textsc{Brigoulet}, Franck \textsc{Glaziou}, } + +{\Large Pascal \textsc{Lafourcade} et Marie-Fran\c{c}oise + \textsc{Servajean}} + + +\vfill + + +\begin{tikzpicture} + +%%% un triangle + +%% horizonatale +\draw[blue,line width=1pt] (-1,0) -- (1,0); +\draw[blue,line width=1pt] (-2.5,-.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (-1.5,-1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (0,3.5) -- (1,3.5); + +%% Croissante +\draw[blue,line width=1pt] (0,0) -- (1,1.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (0,3.5); +\draw[blue,line width=1pt] (-1,0) -- (1,3.5); +\draw[blue,line width=1pt] (3,-1.75) -- (3.5,-0.75); + +%% Decroissante +\draw[blue,line width=1pt] (0.5,.875) -- (1.5,-.875); +\draw[blue,line width=1pt] (1,1.75) -- (3,-1.75); +\draw[blue,line width=1pt] (1,3.5) -- (3.5,-0.75); +\draw[blue,line width=1pt] (-2.5,-.875) -- (-1.5,-1.75); + + + +\end{tikzpicture} + +%% \begin{tikzpicture} + +%% %%% un cube + +%% \draw[red,line width=1pt] (0,.5) -- (1,0); +%% \draw[red,line width=1pt] (2,.5) -- (1,0); + +%% \draw[red,line width=1pt] (0,1.5) -- (1,1); +%% %\draw[red,line width=1pt] (0,1.5) -- (1,2); +%% \draw[red,line width=1pt] (0,1.5) -- (.5,1.75); +%% %\draw[red,line width=1pt] (2,1.5) -- (1,2); +%% \draw[red,line width=1pt] (2,1.5) -- (1.5,1.75); +%% \draw[red,line width=1pt] (2,1.5) -- (1,1); + +%% \draw[red,line width=1pt] (1,1) -- (1,0); +%% \draw[red,line width=1pt] (0,1.5) -- (0,.5); +%% \draw[red,line width=1pt] (2,1.5) -- (2,.5); + +%% %% droite + +%% %\draw[red,line width=1pt] (1.5,1.25) -- (2.5,0.75); +%% \draw[red,line width=1pt] (2,1) -- (2.5,0.75); +%% \draw[red,line width=1pt] (3.5,1.25) -- (2.5,0.75); + +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,1.75); +%% \draw[red,line width=1pt] (1.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,2.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (2.5,1.75); + +%% \draw[red,line width=1pt] (2.5,1.75) -- (2.5,.75); +%% %\draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.25); +%% \draw[red,line width=1pt] (1.5,2.25) -- (1.5,1.75); +%% \draw[red,line width=1pt] (3.5,2.25) -- (3.5,1.25); + +%% %% Haut +%% \draw[red,line width=1pt] (0,2) -- (1,1.5); +%% %\draw[red,line width=1pt] (2,2) -- (1,1.5); +%% \draw[red,line width=1pt] (1.5,1.75) -- (1,1.5); + +%% \draw[red,line width=1pt] (0,3) -- (1,2.5); +%% \draw[red,line width=1pt] (0,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,3.5); +%% \draw[red,line width=1pt] (2,3) -- (1,2.5); + +%% \draw[red,line width=1pt] (1,2.5) -- (1,1.5); +%% \draw[red,line width=1pt] (0,3) -- (0,2); +%% %\draw[red,line width=1pt] (2,3) -- (2,2); +%% \draw[red,line width=1pt] (2,3) -- (2,2.5); + + +%% \end{tikzpicture} + +\vfill + + +\includegraphics[width=5cm]{iut-uca.png} +\end{center} + +\vfill + +{\Large Nom : \\ + +Prénom : \\ + +Groupe : \\ +} +%\url{http://mocodo.wingi.net/} + +%\url{http://mirror.hmc.edu/ctan/graphics/pgf/contrib/tkz-orm/tkz-orm.pdf} + + + +\end{titlepage} + +%% \section*{Avant Propos} + +%% L’objectif de ce cours de base de données avancées est de +%% présenter + + + +%% \newpage + +\tableofcontents + +\newpage + +\section*{Interface \proc{}} + +\proc{} est une interface entre le langage C et le SGBD Oracle. Il +s'agit d'une interface de précompilation, c'est-à-dire que le +programmeur écrit ses ordres SQL dans son code C et ceux-ci sont +traduits par un précompilateur. Le rôle du précompilateur est de +traduire un programme comprenant des commandes SQL en un programme ne +comprenant que des instructions du langage C et pouvant accéder à la +base de données (voir Figure~\ref{fig:proc}). Il s'agit de remplacer +les commandes SQL par des appels à des modules Oracle combinant ainsi +les avantages d'un langage procédural C à ceux d'un langage non +procédural SQL. + +\begin{figure}[htb] +\begin{center} + \includegraphics[width=12cm]{proc.png} +\end{center} +\caption{Illustration du processus permettant d'utiliser un fichier \proc{}}\label{fig:proc} +\end{figure} + +La précompilation, la compilation et l'édition de liens de tels programmes sont masquées par l’exécution d’une commande sur les fichiers sources qui doivent être suffixés par « \code{.pc} ». + +\section{Structure d’un programme \proc{}} + +Un fichier \proc{} se structure de la même manière qu’un fichier C. En +plus des commandes SQL, il faut simplement penser à la connexion et la +déconnexion à la base de données. Il est donc important de préparer la +liaison entre C et Oracle. Pour cela il faut déclarer un ensemble de +variables de communication et une zone de communication pour récupérer +les comptes rendus Oracle. + +\subsection{La section \code{INCLUDE} : (même fonction que le include du C).} + +Le fichier \code{SQLCA} permet de connaître le résultat d'une commande +\proc{} (erreur, nombre de lignes résultant de la requête, ...). La +syntaxe est la suivante : \code{EXEC SQL INCLUDE SQLCA.H;} + +\subsection{La déclaration de variables} + +La déclaration des variables hôtes, c'est-à-dire les variables +utilisées dans les commandes SQL, s’effectue exactement de la même +manière qu’en C. +\begin{verbatim} +int pemno; +VARCHAR pname[11]; +int pdeptno; +\end{verbatim} +Il est important de noter qu’une variable hôte : +\begin{itemize} +\item doit être précédée de '\code{:}' lorsqu'elle est utilisée (sauf + lors de la déclaration), +\item ne doit pas être un mot réservé SQL. +\end{itemize} + +\proc{} permet l'utilisation du type \code{VARCHAR} pour travailler +avec les chaînes de caractères de longueur variable. C’est le seul +type SQL qui peut être utilisé. Il est important de toujours choisir +avec attention les types C car ils vont contenir les informations +issues des types SQL. Par exemple, \code{NUMBER(8,2)} ne peut pas +tenir dans un \code{int}. Il est important de noter que chaque +variable de type \code{VARCHAR} va être traduite par le précompilateur +par une structure C. \code{VARCHAR poste[40];} Le code ci-dessus va +être traduit ainsi : +\begin{verbatim} +struct { + unsigned int len; /* longueur de la chaîne */ + unsigned char arr[40]; /* la chaîne elle-même */ +} poste ; +\end{verbatim} +L’utilisation de \code{VARCHAR} permet donc de s’abstraire de la +gestion du \verb+‘\0’+ qui n’est pas reconnu par Oracle. Ainsi la +longueur de la chaîne est celle située dans l'entier \code{len}. En +sortie d'une commande, Oracle complète la chaîne avec des espaces à +droite et met à jour la longueur. Pour entrer une commande, il faut +faire attention \`a cela. + +\subsection{La connexion à la base de données} + +Le plus simple est souvent de définir une fonction \`a réutiliser à +chaque fois. + +\begin{verbatim} +void connexion() +{ VARCHAR uid[50]; + char login[20]; + char passwd[20]; + printf("Donner votre login : "); + scanf("%s",login); + printf("\nDonnez votre mot de passe Oracle : "); + scanf("%s",passwd); + printf("\n"); + strcpy(uid.arr,login); + strcat(uid.arr,"/"); + strcat(uid.arr,passwd); + strcat(uid.arr,"@kirov"); + uid.len=strlen(uid.arr); + + EXEC SQL CONNECT :uid; + if (sqlca.sqlcode==0) + printf(" Connexion réussie avec succès.\n\n"); + else + { + printf ("Problème à la connexion.\n\n"); + exit(1); + } +} +\end{verbatim} +Pour la déconnexion, le même principe est à utiliser. Cela permet +d’appeler la fonction déclarée à chaque fois que nécessaire. Il est +possible de pr\'evoir le cas où il faut valider les transactions et +les cas où il faut les annuler. +\begin{verbatim} +void deconnexion(int validation) +{ + if (validation == 1) + { + EXEC SQL COMMIT WORK RELEASE; + } else + { + EXEC SQL ROLLBACK WORK RELEASE; + } + printf("Déconnexion sans problème.\n"); +} +\end{verbatim} +\subsection{Le corps de l'application} + +Il contient essentiellement des ordres SQL aussi bien pour la +manipulation de données que pour la définition des données. La syntaxe +utilisée est la même que celle de PL/SQL avec en plus l'utilisation +possible de variables hôtes partout où une constante peut être +employée (nom de relation, nom d'attribut,...). + +\begin{verbatim} +EXEC SQL CREATE TABLE empTest(empno NUMBER(2)); + +EXC SQL INSERT INTO tligne VALUES('exception produit inexistant'); + +EXEC SQL SELECT job INTO :function FROM emp WHERE noemp=301; + +EXEC SQL UPDATE emp SET sal = :sal WHERE noemp = :noemp; + +EXEC SQL DELETE FROM emp WHERE noemp = :noemp; +\end{verbatim} +Toutes les sortes de requêtes peuvent être utilisées. Les requêtes +\code{SELECT} suivent exactement les mêmes règles qu’en PL/SQL. Dans +l’exemple précédent, le \code{SELECT} doit retourner une et une seule +ligne. L’utilisation des curseurs pour les multi-lignes est présentée +après. + +\begin{exercice}~ +\begin{enumerate} +\item \'Ecrire un programme Pro-C qui se connecte à Kirov puis affiche + le nombre de produits contenus dans la base de données, puis se + déconnecte. + +\begin{SaveVerbatim}{countprod} +int q1(void) { + int nbProd; + EXEC SQL SELECT COUNT(*) INTO nbProd FROM TPRODUIT; + printf("Il y a %d produits en base.\n", nbProd); + return nbProd; +} +\end{SaveVerbatim} +\cache{\tiny \BUseVerbatim{countprod}} + +\item \'Ecrire un programme Pro-C qui demande à l’utilisateur un + produit et l’ajoute à la BD. + +\begin{SaveVerbatim}{addprod} + void q2(void) { + char codeRayon[REFERENCE_LEN], dateStock[DATE_LEN], nCodeRayon[REFERENCE_LEN], + nDateStock[DATE_LEN], noProd[REFERENCE_LEN]; + int choix, nStock, stock; + float nPrixV, prixV; + VARCHAR des[VARCHAR_LEN], nDes[VARCHAR_LEN]; + printf("Saisir numéro produit : "); + scanf("%s%*c", noProd); + EXEC SQL SELECT des, stock, prixV, codeRayon, dateStock + INTO :des, :stock, :prixV, :codeRayon, :dateStock + FROM TPRODUIT + WHERE noProd = :noProd; + printf("1 - Désignation : %.*s.\n", des.len, des.arr); + printf("2 - Stock : %d.\n", stock); + printf("3 - Prix de vente : %.2f euro.\n", prixV); + printf("4 - Code rayon : %s.\n", codeRayon); + printf("5 - Date : %s.\n", dateStock); + while (choix != 9) { + printf("Que voulez-vous modifier (9: quitter) ?\n"); + scanf("%d%*c", &choix); + switch (choix) { + case 1: + printf("Entrez la nouvelle désignation : "); + fgets(nDes, sizeof nDes, stdin); + if (nDes[strlen(nDes) - 1] == '\n') { + nDes[strlen(nDes) - 1] = '\0'; + } + EXEC SQL UPDATE TPRODUIT SET des = :nDes WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) {erreur_sql(STOP);} + break; + case 2: + printf("Entrez le nouveau stock : "); + scanf("%d%*c", &nStock); + EXEC SQL UPDATE TPRODUIT SET stock = :nStock WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) {erreur_sql(STOP);} + break; + case 3: + printf("Entrez le nouveau prix : "); + scanf("%f%*c", &nPrixV); + EXEC SQL UPDATE TPRODUIT SET prixV = :nPrixV WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) {erreur_sql(STOP);} + break; + case 4: + printf("Entrez le nouveau code rayon : "); + scanf("%s", &nCodeRayon); + EXEC SQL UPDATE TPRODUIT SET codeRayon = :nCodeRayon WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) {erreur_sql(STOP);} break; + case 5: + printf("Entrez la date : "); + scanf("%s", &nDateStock); + EXEC SQL UPDATE TPRODUIT SET dateStock = :nDateStock WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) {erreur_sql(STOP);} + break; + default: + printf("Choix inconnu.\n"); + break; } + EXEC SQL COMMIT;}} +\end{SaveVerbatim} + +\cache{\scriptsize \BUseVerbatim{addprod}} + +\end{enumerate} +\end{exercice} + +\subsection{Le traitement des erreurs} +\subsubsection{Le fichier \code{SQLCA.H}} +Il définit une structure de données '\code{sqlca}' dont les champs +sont mis à jour après chaque exécution d'un ordre SQL et qui en donne +le compte rendu. + +\begin{verbatim} +struct { + long sqlcode; /* code resultant de l'exécution + =0 -> ok, + >0 -> ok avec un code d'état, + <0 -> erreur */ + + struct { + unsigned short sqlerrml; /*longueur du message*/ + char sqlerrmc[70]; /*message d'erreur*/ + } sqlerrm; + + long sqlerrd[6]; /* seul sqlerrd[2] est utilisé -> donne le nombre de lignes modifiées + UPDATE ou rajoutées par INSERT ou ramenées par un SELECT*/ + + char sqlwarn[8]; /*sqlwarn[0] 'W’ -> warning*/ + sqlwarn[0] = '' /*-> pas de warning*/ + sqlwarn[1] = 'W' /*-> troncation numérique ou char*/ + sqlwarn[2] = 'W' /*-> valeur Null est ignore*/ + sqlwarn[3] = 'W' /*-> plus de champs dans SELECT que de variables pour recevoir*/ + sqlwarn[4] = 'W' /*-> toutes les lignes d'une table sont touchées (par DELETE ou UPDATE par + exemple)*/ + sqlwarn[5] /*inutilisé*/ + sqlwarn[6] = 'W' /*-> Oracle a dû exécuter un rollback*/ + sqlwarn[7] = 'W' /*-> la donnée ramenée par un FETCH a été modifié depuis que la clause + SELECT a été execute*/ +} sqlca; +\end{verbatim} +Après chaque commande SQL il est possible de tester le champ de +\code{sqlca} correspondant à une erreur possible dans le cadre de +cette commande. +\subsection{La commande \code{WHENEVER}} + +Oracle permet d'utiliser des directives qui spécifient le traitement à +effectuer en cas d'erreur. +\begin{verbatim} +EXEC SQL WHENEVER [SQLERROR|SQLWARNING|NOT FOUND][STOP|CONTINUE|GOTO
’;+ + +\verb+SELECT * FROM user_cons_columns WHERE table_name='
";+ + +\verb+show errros+ affiche les erreurs des fonctions. + + + +\paragraph{Contraintes :} Description d'une table : \verb+describe
+ ou +\verb+desc
+; + +Liste des colonnes concernées par les contraintes : +\verb+SELECT * FROM user_cons_columns;+ + +Lire une table d'un autre schéma : + +\verb+SELECT * FROM .; -- ou schma = login de connexion de l'utilisateur+ + + + +\paragraph{Affichage :} +\verb+SET HEADING OFF+ + +\verb+SET FEEDBACK OFF+ + +\paragraph{Travailler \`a la maison} + +Il est possible d'acc\`eder par SSH \`a la machine +\texttt{londres}. L'adresse de la passerelle est +\texttt{ssh.iut-clermont.uca.fr} qui n'est accessible que par une +authentification avec des clefs SSH. + +Cet acc\`es vous permettra d'acc\`eder au serveur de base de donn\'ees +comme lorsque vous travailler \`a l'IUT. Avant de pouvoir se +connecter, il faut activer l'acc\`es \`a l'IUT sur +\texttt{http://berlin.iut.local} ce qui peut prendre 30 minutes. + +Pour d\'eposer vos clefs vous pouvez utiliser +\url{https://homeweb.iut-clermont.uca.fr} + +%.ssh/authorized_keys +%londres.iut.local +%SSH http://cr2i.intranet.iut.local/site/page/documentation/ssh/ + + +%% Faire du SQLPLUS depuis chez-vous en faisant du SSH en tapant cette +%% commande où vous devez remplacer LOGIN par votre login pour vous +%% connecter sur Linux à l'IUT: \verb+ssh LOGIN@193.49.118.206+ + +%% Le workflow le plus propre est d'avoir un fichier sur votre machine +%% personnelle que vous copier en faisant un \code{scp} sur la machine + +%% Par exemple la commande ci-dessous copie le fichier +%% creation-donnees.sql de mon ordintaeur sur la machine virtuelle + +%% \verb+scp creation-donnees.sql palafour@193.49.118.206:.+ + +%% Par contre une fois que je suis déconnecté de ma connexion ssh tous +%% les fichiers peuvent \^etre détruits car votre repertoire personnel +%% (home) sur ce serveur est TEMPORAIRE. Vos donnees peuvent etre +%% perdues a tout moment. Ne stocker RIEN ici. + + + +\paragraph{En cas de blocage :} + +Dans un terminal executer la commande suivante pour voir les \code{pid} +des processus zombies : \verb+ps -aux | grep sqlplus+ + +Ensuite tuer ces zombies gr\^ace \`a la commande \code{kill -9 numerodepid} + \newpage + %\newpage + +%\printindex + \end{document} + + + diff --git a/COURS/compil.sh b/COURS/compil.sh new file mode 100755 index 0000000..6884021 --- /dev/null +++ b/COURS/compil.sh @@ -0,0 +1,3 @@ +make -f /etc/oracle/proc.mk build EXE=$1 OBJS=$1.o +./$1 + diff --git a/COURS/hopital-q1.pc b/COURS/hopital-q1.pc new file mode 100755 index 0000000..bec4dc4 --- /dev/null +++ b/COURS/hopital-q1.pc @@ -0,0 +1,150 @@ +#include +#include +#include +#define size_t long + +EXEC SQL INCLUDE SQLCA.H; +EXEC SQL INCLUDE SQLDA.H; +EXEC SQL INCLUDE ORACA.H; + + +void connexion() +{ VARCHAR uid[50]; + char login[20]; + char passwd[20]; + printf("\n"); + strcpy(uid.arr,"palafour"); + strcat(uid.arr,"/"); + strcat(uid.arr,"1s;ph;;1"); + strcat(uid.arr,"@kirov"); + uid.len=strlen(uid.arr); + EXEC SQL CONNECT :uid; + if (sqlca.sqlcode==0) + printf(" Connexion réussie avec succès.\n\n"); + else + { + printf ("Problème à la connexion.\n\n"); + exit(1); + } +} +void deconnexion(int validation) +{ + if (validation == 1) + { + EXEC SQL COMMIT WORK RELEASE; + } + else + { + EXEC SQL ROLLBACK WORK RELEASE; + } + printf("\nDéconnexion sans problème.\n"); +} + + +void sql_error(char *msg) +{ + char err_msg[128]; + long buf_len, msg_len; + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + buf_len = sizeof (err_msg); + sqlglm(err_msg, &buf_len, &msg_len); + if (msg_len > buf_len) + msg_len = buf_len; + printf("%.*s\n", msg_len, err_msg); + deconnexion(0); + exit(1); +} + + +void traitErreur(char *msg) +{ + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + deconnexion(0); + exit(1); +} + + +int main(int argc, char** argv) +{ +varchar vnom[20]; +varchar vprenom[20]; +varchar vhopital[20]; +char vidhopital[6]; +int fini; +int fin=1; +int vnbnom; +int vnbhopit; +int nb=1; + + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + printf("\n Appel de la fonction connexion"); + connexion(); + printf("\n Appel de la fonction deconnexion"); + + /*----------------------------------lecture----------------------------*/ + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + + /* SELECT p.Nom, p.Prenom, h.Nom FROM PERSONNEL p, HOPITAL h WHERE h.id_hopital = p.id_hopital and p.id_personnel='PE01'; */ + /* printf("\nUn exemple PE01 \n");*/ + + EXEC SQL SELECT p.Nom, p.Prenom, h.Nom INTO :vnom, :vprenom, :vhopital FROM PERSONNEL p, HOPITAL h WHERE h.id_hopital = p.id_hopital and p.id_personnel='PE01'; + + vnom.len=strlen(vnom.arr); + vprenom.len=strlen(vprenom.arr); + vhopital.len=strlen(vhopital.arr); + + printf("\n TEST pour PE01 : Nom : %.*s prenom : %.*s hopital : %.*s \n", vnom.len, vnom.arr, vprenom.len, vprenom.arr, vhopital.len,vhopital.arr); + + printf("\n Affichage les hopitaux \n"); + + /* SELECT COUNT(h.Nom) FROM HOPITAL h */ + EXEC SQL SELECT COUNT(h.Nom) INTO :vnbhopit FROM HOPITAL h; + printf("\nNombre d'hopitaux est %d\n",vnbhopit); + + EXEC SQL DECLARE hopitaux CURSOR FOR SELECT Nom, id_hopital FROM HOPITAL ORDER by Nom; + EXEC SQL OPEN hopitaux; + + EXEC SQL FETCH hopitaux INTO :vhopital, :vidhopital; + if (sqlca.sqlcode == 1403) {fin = 0;} + while (fin!=0) + { + vhopital.len=strlen(vhopital.arr); + printf("\n Affichage des personnels de l'hopital %.*s : \n",vhopital.len,vhopital.arr); + + /* SELECT COUNT(p.Nom) FROM PERSONNEL WHERE h.id_hopital = p.id_hopital; */ + EXEC SQL SELECT COUNT(Nom) INTO :vnbnom FROM PERSONNEL WHERE id_hopital = :vidhopital; + printf("\nNombre de personnel de l'hopital %.*s est %d\n",vhopital.len,vhopital.arr, vnbnom); + + /* SELECT p.Nom, p.Prenom FROM PERSONNEL p, WHERE h.id_hopital = p.id_hopital ORDER by p.prenom ; */ + EXEC SQL DECLARE personnels CURSOR FOR SELECT Nom, Prenom FROM PERSONNEL WHERE id_hopital = :vidhopital ORDER by prenom; + + EXEC SQL OPEN personnels; + fini=1; + EXEC SQL FETCH personnels INTO :vnom, :vprenom; + if (sqlca.sqlcode == 1403) {fini = 0;} + + while (fini!=0) + { + vnom.len=strlen(vnom.arr); + vprenom.len=strlen(vprenom.arr); + + printf("%d) Nom : %.*s Prenom : %.*s \n", nb, vnom.len, vnom.arr, vprenom.len, vprenom.arr); + nb++; + EXEC SQL FETCH personnels INTO :vnom, :vprenom; + if (sqlca.sqlcode == 1403) {fini = 0;} + } + EXEC SQL CLOSE personnels; + + EXEC SQL FETCH hopitaux INTO :vhopital, :vidhopital; + if (sqlca.sqlcode == 1403) {fin = 0;} + } + printf(" Fini \n"); + EXEC SQL CLOSE hopitaux; + + deconnexion(1); + return(0); +} + + diff --git a/COURS/hopital-q2.pc b/COURS/hopital-q2.pc new file mode 100755 index 0000000..fe78035 --- /dev/null +++ b/COURS/hopital-q2.pc @@ -0,0 +1,142 @@ +#include +#include +#include +#define size_t long + +EXEC SQL INCLUDE SQLCA.H; +EXEC SQL INCLUDE SQLDA.H; +EXEC SQL INCLUDE ORACA.H; + + +void connexion() +{ VARCHAR uid[50]; + char login[20]; + char passwd[20]; + printf("\n"); + strcpy(uid.arr,"palafour"); + strcat(uid.arr,"/"); + strcat(uid.arr,"1s;ph;;1"); + strcat(uid.arr,"@kirov"); + uid.len=strlen(uid.arr); + EXEC SQL CONNECT :uid; + if (sqlca.sqlcode==0) + printf(" Connexion réussie avec succès.\n\n"); + else + { + printf ("Problème à la connexion.\n\n"); + exit(1); + } +} +void deconnexion(int validation) +{ + if (validation == 1) + { + EXEC SQL COMMIT WORK RELEASE; + } + else + { + EXEC SQL ROLLBACK WORK RELEASE; + } + printf("\nDéconnexion sans problème.\n"); +} + + +void sql_error(char *msg) +{ + char err_msg[128]; + long buf_len, msg_len; + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + buf_len = sizeof (err_msg); + sqlglm(err_msg, &buf_len, &msg_len); + if (msg_len > buf_len) + msg_len = buf_len; + printf("%.*s\n", msg_len, err_msg); + deconnexion(0); + exit(1); +} + + +void traitErreur(char *msg) +{ + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + deconnexion(0); + exit(1); +} + + +int main(int argc, char** argv) +{ +char vidperso[20]; +char vidfonction[20]; +char vidhopital[6]; +VARCHAR vnom[20]; +VARCHAR vprenom[20]; +char eidperso[20]; +char eidfonction[20]; +char eidhopital[6]; +VARCHAR enom[20]; +VARCHAR eprenom[20]; +int nbhopital=0; +int nbfonction=0; +int nbperso=1; + + + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + printf("\n Appel de la fonction connexion"); + connexion(); + printf("\n Appel de la fonction deconnexion"); + + /*----------------------------------lecture----------------------------*/ + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + + printf("Saisir un nouveau personnel \n"); + printf("Entrer son nom : "); + scanf("%s",vnom.arr); + vnom.len=strlen(vnom.arr); + printf("Entrer son prenom : "); + scanf("%s",vprenom.arr); + vprenom.len=strlen(vprenom.arr); + + do{ + printf("Entrer son id hopital : "); + scanf("%s",vidhopital); + EXEC SQL SELECT COUNT(*) INTO :nbhopital FROM HOPITAL WHERE id_hopital=:vidhopital; + //printf("nbhopital %d\n",nbhopital); + } + while (nbhopital !=1); + + do{ + printf("Entrer son id personnel : "); + scanf("%s",vidperso); + EXEC SQL SELECT COUNT(*) INTO :nbperso FROM PERSONNEL WHERE id_personnel=:vidperso; + if (nbperso==1){ + printf("Ce numero de personnel existe deja\n"); + EXEC SQL SELECT * INTO :eidperso, :eidfonction, :eidhopital, :enom, :eprenom FROM PERSONNEL WHERE id_personnel=:vidperso; + printf("ID PERSO : %s \n",eidperso); + printf("ID FONCTION : %s \n",eidfonction); + printf("ID HOPITAL : %s \n",eidhopital); + printf("NOM : %s \n",enom.arr); + printf("PRENOM : %s \n",eprenom.arr); + } + } + while (nbperso !=0); + + do{ + printf("Entrer son id fonction : "); + scanf("%s",vidfonction); + EXEC SQL SELECT COUNT(*) INTO :nbfonction FROM FONCTION WHERE id_fonction=:vidfonction; + } + while (nbfonction !=1); + + EXEC SQL INSERT INTO PERSONNEL VALUES (:vidperso,:vidfonction,:vidhopital,:vnom,:vprenom); + + EXEC SQL COMMIT; + + + deconnexion(1); + return(0); +} + + diff --git a/COURS/iut-uca.png b/COURS/iut-uca.png new file mode 100644 index 0000000..bbd0daa Binary files /dev/null and b/COURS/iut-uca.png differ diff --git a/COURS/menu.pc b/COURS/menu.pc new file mode 100755 index 0000000..9376acf --- /dev/null +++ b/COURS/menu.pc @@ -0,0 +1,312 @@ +#include +#include +#include +#define size_t long + +EXEC SQL INCLUDE SQLCA.H; +EXEC SQL INCLUDE SQLDA.H; +EXEC SQL INCLUDE ORACA.H; + +void connexion() +{ VARCHAR uid[50]; + char login[20]; + char passwd[20]; + printf("\n"); + strcpy(uid.arr,"palafour2"); + strcat(uid.arr,"/"); + strcat(uid.arr,"palafour2"); + strcat(uid.arr,"@kirov"); + uid.len=strlen(uid.arr); + EXEC SQL CONNECT :uid; + + if (sqlca.sqlcode==0) + printf(" Connexion réussie avec succès.\n\n"); + else + { + printf ("Problème à la connexion.\n\n"); + exit(1); + } +} +void deconnexion(int validation) +{ + if (validation == 1) + { + EXEC SQL COMMIT WORK RELEASE; + } + else + { + EXEC SQL ROLLBACK WORK RELEASE; + } + printf("\nDéconnexion sans problème.\n"); +} + + +void sql_error(char *msg) +{ + char err_msg[128]; + long buf_len, msg_len; + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + buf_len = sizeof (err_msg); + sqlglm(err_msg, &buf_len, &msg_len); + if (msg_len > buf_len) + msg_len = buf_len; + printf("%.*s\n", msg_len, err_msg); + deconnexion(0); + exit(1); +} + + +void traitErreur(char *msg) +{ + EXEC SQL WHENEVER SQLERROR CONTINUE; + printf("%s\n", msg); + deconnexion(0); + exit(1); +} + + +void saisie(void) +{ +varchar nocl[4]; +varchar nom[80]; +varchar ville[80]; +int cp; + + printf("Saisir une nouveau client \n"); + printf("Entrer le nom du client : "); + scanf("%s",nom.arr); + nom.len=strlen(nom.arr); + printf("Entrer la ville du client : "); + scanf("%s",ville.arr); + ville.len=strlen(ville.arr); + + printf("Entrer le code postal du client : "); + scanf("%d",&cp); + + printf("Entrer le code du client : "); + scanf("%s",nocl.arr); + nocl.len=strlen(nocl.arr); + + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + + EXEC SQL INSERT INTO TClient2017 VALUES (:nocl,:nom,:ville,:cp); + + EXEC SQL COMMIT; +} + +void modification(void){ +varchar noclchange[4]; +varchar nomnew[80]; +varchar villenew[80]; +int cpnew; + +varchar nomold[80]; +varchar villeold[80]; +int cpold; + + printf("Modifier un client \n"); + + printf("Entrer le code du client a modifer : "); + scanf("%s",noclchange.arr); + noclchange.len=strlen(noclchange.arr); + + EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error\n"); + + EXEC SQL SELECT nom, ville, postal INTO :nomold, :villeold, :cpold FROM Tclient2017 WHERE NOCLIENT = :noclchange; + + printf("Nom: %s \n",nomold.arr); + printf("Ville: %s \n",villeold.arr); + printf("CP courant du client: %d \n ",cpold); + + printf("Modifier le nom du client : "); + scanf("%s",nomnew.arr); + nomnew.len=strlen(nomnew.arr); + printf("Modifier la ville du client : "); + scanf("%s",villenew.arr); + villenew.len=strlen(villenew.arr); + printf("Modifier le code postal du client : "); + scanf("%d",&cpnew); + + EXEC SQL UPDATE TClient2017 SET nom = :nomnew, ville = :villenew, postal = :cpnew WHERE noclient = :noclchange; + + EXEC SQL COMMIT; +} + + + +void suppression(void){ + +varchar noclchange[4]; +varchar nomnew[80]; +varchar villenew[80]; +int kmdeb; +int kmfin; +varchar noveh[4]; +varchar datedeb[30]; +varchar dateretour[30]; +int fini=1; + + printf("Supprimer un client \n"); + + printf("Entrer le code du client a supprimer : "); + scanf("%s",noclchange.arr); + noclchange.len=strlen(noclchange.arr); + + EXEC SQL DECLARE locencours CURSOR FOR SELECT noveh, datedeb, kmdeb, dateretprev FROM Tlocation2017 WHERE noclient =:noclchange ; + + EXEC SQL DECLARE locretour CURSOR FOR SELECT noveh, datedeb, kmdeb, kmfin, dateretour FROM Tlocatretour2017 WHERE noclient =:noclchange ; + + EXEC SQL OPEN locencours; + + while (fini=1) + { + EXEC SQL FETCH locencours INTO :noveh, :datedeb, :kmdeb, :dateretour; + printf("noveh: %s datedeb: %s kmdeb : %d date retour: %s \n",noveh.arr,datedeb.arr,kmdeb,dateretour.arr); + if (sqlca.sqlcode == 1403) fini=0; + } + + printf("en retour \n"); + + EXEC SQL CLOSE locencours; + + EXEC SQL OPEN locretour; + + fini=1; + while (fini=1) + { + EXEC SQL FETCH locretour INTO :noveh, :datedeb, :kmdeb, :kmfin, :dateretour; + printf("noveh: %s datedeb: %s kmdeb : %d kmfin : %d date retour: %s \n",noveh.arr,datedeb.arr,kmdeb,kmfin,dateretour.arr); + if (sqlca.sqlcode == 1403) fini=0; + } + + printf("Suppression en cours"); + + EXEC SQL CLOSE locretour; + + EXEC SQL DELETE FROM Tlocation2017 WHERE noclient =:noclchange ; + EXEC SQL DELETE FROM Tlocatretour2017 WHERE noclient =:noclchange ; + + EXEC SQL COMMIT; +} + + +void afficherclient (void){ + +varchar noclient[4]; +varchar nom[80]; +varchar ville[80]; +int postal; +int fini=1; + + printf("Affiche les clients \n"); + + EXEC SQL DECLARE clients CURSOR FOR SELECT noclient, nom, ville, postal FROM Tclient2017; + EXEC SQL OPEN clients; + + while (fini=1) + { + EXEC SQL FETCH clients INTO :noclient, :nom, :ville, :postal; + printf("numero client: %s nom: %s ville : %s CP: %d \n",noclient.arr,nom.arr,ville.arr,postal); + if (sqlca.sqlcode = 1403) fini = 0; + } + printf(" Fini \n"); + EXEC SQL CLOSE clients; +} + + +void afficherlocation (void){ + +varchar nocl[4]; +varchar nom[100][10]; + +varchar noveh[5]; + +varchar immat[50][10]; +varchar datedeb[50][30]; +varchar dateretour[50][30]; +int i; + + printf("Affiche les locations d'un client \n"); + printf("Entrer le numera du client : "); + scanf("%s",nocl.arr); + nocl.len=strlen(nocl.arr); + + EXEC SQL SELECT immat, datedeb, dateretour INTO :immat, :datedeb, :dateretour FROM Tvehicule2017, Tlocatretour2017 WHERE Tlocatretour2017.nocl = :nocl and Tlocatretour2017.noveh = Tvehicule2017.noveh ; + + printf("Il y a %d lignes selectionnees\n",sqlca.sqlerrd[2]); + i=0; + + while (i +#include +#include +#include + +EXEC SQL INCLUDE SQLCA.H; +EXEC SQL INCLUDE SQLDA.H; +EXEC SQL INCLUDE ORACA.H; + +#define CLEAR system("clear") + +/********** Constantes **********/ +#define CONTINUE 0 +#define DATE_LEN 11 +#define DEPT_LEN 3 +#define NOM_LEN 21 +#define NOT_FOUND 1403 +#define REFERENCE_LEN 5 +#define SQL_COMMIT 1 +#define SQL_ROLLBACK 0 +#define SQL_SUCCESS 0 +#define STOP 1 +#define UID_LEN 30 +#define VARCHAR_LEN 51 + +/********** Liste des fonctions **********/ +void connexion(void); +void erreur_sql(int arret); +void deconnexion(int validation); +void q1(void); +int q1bis(void); +void q2(void); +void q3(void); +void q4(void); +void q5(void); +void q6(void); +void q7(void); +/* + * Fonction de connexion à Oracle. + * + * Les identifiants sont rentrés en dur pour ne pas avoir à les retaper + * à la main à chaque test, mais dans l'idéal, on demande à l'utilisateur + * de les rentrer et on concatène les identifiants à uid.arr. + */ +void connexion(void) { + VARCHAR uid[UID_LEN]; + char identifiants[UID_LEN] = "danguyen1/danguyen1@kirov"; + printf("Connexion avec les identifiants suivants : %s .\n", identifiants); + strcpy(uid.arr, identifiants); + uid.len = strlen(uid.arr); + + EXEC SQL CONNECT :uid; + if (sqlca.sqlcode == SQL_SUCCESS) { + printf("Connexion réussie avec succès !\n\n"); + } + else { + printf("Connexion échouée !\n\n"); + exit(EXIT_FAILURE); + } +} + +/* + * Fonction qui affiche les code et message d'erreur SQL. + * + * Paramètres : + * arret STOP(1) pour quitter, n'importe quoi pour continuer + */ +void erreur_sql(int arret) { + printf("Code d'erreur : %d.\n", sqlca.sqlcode); + printf("Message erreur : %.*s.\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); + if (arret == STOP) { + deconnexion(SQL_ROLLBACK); + exit(EXIT_FAILURE); + } +} + +/* + * Fonction de déconnexion. + * + * Paramètres : + * validation SQL_COMMIT(1) pour COMMIT, n'importe quoi pour ROLLBACK + */ +void deconnexion(int validation) { + if (validation == SQL_COMMIT) { + EXEC SQL COMMIT WORK RELEASE; + } + else { + EXEC SQL ROLLBACK WORK RELEASE; + } + printf("Déconnexion réussie, travail %s.\n", validation == 1 ? "enregistré" : "annulé"); +} + +/* + * Affiche le nombre de produits contenus dans la base (utilisée dans la question 3 + * car pas d'intérêt à être utilisée toute seule). + * + * Retourne : + * le nombre de produits contenus dans la base + */ +int q1(void) { + int nbProd; + EXEC SQL SELECT COUNT(*) INTO nbProd FROM TPRODUIT; + printf("Il y a %d produits en base.\n", nbProd); + return nbProd; +} + +/* + * Modifie un produit en affichant ses anciennes valeurs. + */ +void q2(void) { + char codeRayon[REFERENCE_LEN], dateStock[DATE_LEN], nCodeRayon[REFERENCE_LEN], nDateStock[DATE_LEN], noProd[REFERENCE_LEN]; + int choix, nStock, stock; + float nPrixV, prixV; + VARCHAR des[VARCHAR_LEN], nDes[VARCHAR_LEN]; + + printf("Saisir numéro produit : "); + scanf("%s%*c", noProd); + + EXEC SQL + SELECT des, stock, prixV, codeRayon, dateStock + INTO :des, :stock, :prixV, :codeRayon, :dateStock + FROM TPRODUIT + WHERE noProd = :noProd; + + printf("1 - Désignation : %.*s.\n", des.len, des.arr); + printf("2 - Stock : %d.\n", stock); + printf("3 - Prix de vente : %.2f€.\n", prixV); + printf("4 - Code rayon : %s.\n", codeRayon); + printf("5 - Date : %s.\n", dateStock); + + while (choix != 9) { + printf("Que voulez-vous modifier (9: quitter) ?\n"); + scanf("%d%*c", &choix); + + switch (choix) { + case 1: + printf("Entrez la nouvelle désignation : "); + fgets(nDes, sizeof nDes, stdin); + if (nDes[strlen(nDes) - 1] == '\n') { + nDes[strlen(nDes) - 1] = '\0'; + } + EXEC SQL + UPDATE TPRODUIT + SET des = :nDes + WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + break; + case 2: + printf("Entrez le nouveau stock : "); + scanf("%d%*c", &nStock); + EXEC SQL + UPDATE TPRODUIT + SET stock = :nStock + WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + break; + case 3: + printf("Entrez le nouveau prix : "); + scanf("%f%*c", &nPrixV); + EXEC SQL + UPDATE TPRODUIT + SET prixV = :nPrixV + WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + break; + case 4: + printf("Entrez le nouveau code rayon : "); + scanf("%s", &nCodeRayon); + EXEC SQL + UPDATE TPRODUIT + SET codeRayon = :nCodeRayon + WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + break; + case 5: + printf("Entrez la date : "); + scanf("%s", &nDateStock); + EXEC SQL + UPDATE TPRODUIT + SET dateStock = :nDateStock + WHERE noProd = :noProd; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + break; + default: + printf("Choix inconnu.\n"); + break; + } + EXEC SQL COMMIT; + } +} + +/* + * Affiche le nombre de produits en base et les affiche. + */ +void q3(void) { + char noProd[REFERENCE_LEN], codeRayon[REFERENCE_LEN], dateStock[DATE_LEN]; + int cpt = 0, nbProd, stock; + float prixV; + VARCHAR des[REFERENCE_LEN1]; + + nbProd = q1bis(); + if (nbProd > 0) { + EXEC SQL + DECLARE cprod CURSOR FOR + SELECT noProd, des, stock, prixV, codeRayon, dateStock + FROM TPRODUIT; + EXEC SQL OPEN cprod; + EXEC SQL FETCH cprod INTO :noProd, :des, :stock, :prixV, :codeRayon, :dateStock; + + while (sqlca.sqlcode != NOT_FOUND) { + printf("----- Produit n°%d -----\n", ++cpt); + printf("Numéro produit : %s.\n", noProd); + printf("Désignation : %.*s.\n", des.len, des.arr); + printf("Stock : %d.\n", stock); + printf("Prix de vente : %.2f.\n", prixV); + printf("Code rayon : %s.\n", codeRayon); + printf("Date stock : %s.\n", dateStock); + EXEC SQL + FETCH cprod INTO :noProd, :des, :stock, :prixV, :codeRayon, :dateStock; + if (sqlca.sqlcode < SQL_SUCCESS) { + erreur_sql(STOP); + } + } + EXEC SQL CLOSE cprod; + } +} + +/* + * Ajoute un produit saisi. + */ +void q4(void) { + char choix, noProd[REFERENCE_LEN], dateStock[DATE_LEN]; + int stock; + float prixV; + short indicateurDes = 0, indicateurStock = 0, indicateurPrixV = 0, indicateurCodeRayon = 0, indicateurDateStock = 0; + VARCHAR des[VARCHAR_LEN]; + + printf("Saisir numéro produit : "); + scanf("%s%*c", noProd); + printf("Saisir une désignation (O/*) ? "); + scanf("%c%*c", &choix); + if (toUpper(choix) == 'O') { + printf("Saisir la désignation : "); + fgets(des, sizeof des, stdin); + if (des[strlen(des) - 1] == '\n') { + des[strlen(des) - 1] = '\0'; + } + } + else { + indicateurDes = -1; + } + + printf("Saisir un stock (O/*) ? "); + scanf("%c%*c", &choix); + if (toUpper(choix) == 'O') { + printf("Saisir le stock : "); + scanf("%d%*c", &stock); + } + else { + indicateurStock = -1; + } + + printf("Saisir un prix de vente : "); + scanf("%c%*c", &choix); + if (toUpper(choix) == 'O') { + printf("Saisir le prix de vente : "); + scanf("%f%*c", &prixV); + } + else { + indicateurPrixV = -1; + } + + printf("Saisir un code rayon (O/*) ? "); + scanf("%c%*c", &choix); + if (toUpper(choix) == 'O') { + printf("Saisir le code rayon : "); + scanf("%d%*c", codeRayon); + } + else { + indicateurCodeRayon = -1; + } + + if (indicateurStock == 0) { + EXEC SQL + SELECT SYSDATE + INTO :dateStock + FROM DUAL; + + } + else { + indicateurDateStock = -1; + } + + EXEC SQL + INSERT INTO TPRODUIT + VALUES( + :noProd, + :des INDICATOR :indicateurDes, + :stock INDICATOR :indicateurStock, + :codeRayon INDICATOR :indicateurCodeRayon, + :dateStock INDICATOR :indicateurDateStock + ); + + EXEC SQL COMMIT; +} + +/* + * Affiche les produits d'un fournisseur saisi. + */ +void q5(void) { + char noProd[REFERENCE_LEN], refFourn[REFERENCE_LEN]; + printf("Saisir référence fournisseur : "); + scanf("%s%*c", refFourn); + + EXEC SQL + DECLARE cprod CURSOR FOR + SELECT noProd + FROM TPRODUITFOURN + WHERE pf.refFourn = :refFourn; + + EXEC SQL OPEN cprod; + + EXEC SQL FETCH cprod INTO :noProd; + if (sqlca.sqlcode == NOT_FOUND) { + printf("Aucun produit trouvé !\n"); + } + + printf("Liste des numéros de produits pour ce fournisseur :\n"); + while (sqlca.sqlcode != NOT_FOUND) { + printf("\t%s\n", noProd); + EXEC SQL FETCH cprod INTO :noProd; + + } + + EXEC SQL + CLOSE cprod; +} + +/* + * Enregistre un fournisseur saisi. + */ +void q6(void) { + char refFourn[REFERENCE_LEN], dept[DEPT_LEN]; + VARCHAR nom[NOM_LEN]; + + printf("Saisir la référence fournisseur : "); + scanf("%s%*c", refFourn); + printf("Saisir le département : "); + scanf("%s%*c", dept); + printf("Saisir le nom du fournisseur : "); + fgets(nom, sizeof nom, stdin); + if (nom[strlen(nom) - 1] == '\n') { + nom[strlen(nom) - 1] = '\0'; + } + + EXEC SQL + INSERT INTO TFOURNISSEUR + VALUES(:refFourn, :nom, :dept); + + EXEC SQL COMMIT; +} + +/* + * Supprime un fournisseur en prenant le soin de supprimer ses produits de la table de liaison. + */ +void q7(void) { + char refFourn[REFERENCE_LEN]; + + printf("Saisir la référence du fournisseur à supprimer : "); + scanf("%s%*c", refFourn); + + EXEC SQL + DELETE FROM TPRODUITFOURN + WHERE refFourn = :refFourn; + + EXEC SQL + DELETE FROM TFOURNISSEUR + WHERE refFourn = :refFourn; +} + +/* + * Fonction principale. + * + * Paramètres : + * argc Le nombre d'arguments + * argv Le tableau d'arguments + * + * Retourne : + * le code de retour défini dans stdlib.h + * (EXIT_SUCCESS = 0) + */ +int main(int argc, char const *argv[]) { + int validation; + + CLEAR; + + connexion(); + + EXEC SQL + WHENEVER SQLERROR + DO erreur_sql(STOP); + + // qX(); + + printf("Enregistrer le travail ? (1 = oui, * = non)\n"); + scanf("%d%*c", &validation); + deconnexion(validation); + + return EXIT_SUCCESS; +} diff --git a/EXOS/Exam2019-annexe.tex b/EXOS/Exam2019-annexe.tex new file mode 100644 index 0000000..e585b23 --- /dev/null +++ b/EXOS/Exam2019-annexe.tex @@ -0,0 +1,174 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{url} +\usepackage{comment} +\usepackage{fancyhdr}% fancy header +\usepackage{multirow} +\usepackage{slashbox} + +\usepackage{color, colortbl} +\definecolor{Gray}{gray}{0.9} +\usepackage{adjustbox} +\usepackage{slashbox} +%\usepackage{times} +\usepackage{tikz,pgflibraryarrows,pgffor,pgflibrarysnakes} +\usetikzlibrary{decorations.pathreplacing} + +\usepackage{pdfpages} + +\usepackage{fancyvrb} + +\fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries 2018-2019 BD PLS/SQL\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries ~\leftmark } + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{}%\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + +\usepackage{amsmath} +\usepackage{amsthm} + + + +\theoremstyle{definition} +\newtheorem{exercice}{Exercice} + +\pagestyle{monstyle} + +\usepackage{amsmath} +\usepackage{amsthm} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} +\usepackage{setspace} + + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +\cachefalse % version prof +%\cachetrue % version etudiant + + + +\begin{document} + +\section*{NBA} + +\begin{verbatim} + +CREATE TABLE JOUEUR(id_joueur CHAR(6) PRIMARY KEY, +Nom VARCHAR2(20), +Prenom VARCHAR2(20), +Date_de_naissance DATE, +Taille NUMBER, +Poste char(2) constraint c_poste CHECK (Poste IN('PG','SG','SF','PF','C'))); + +CREATE TABLE EQUIPE(id_equipe CHAR(6) PRIMARY KEY, +Nom VARCHAR2(20), +Ville VARCHAR2(20), +Conference VARCHAR2(5) constraint c_conf check (Conference in('Est','Ouest')), +Date_creation DATE); + +CREATE TABLE GAME(id_game CHAR(6) PRIMARY KEY, +Date_game DATE, +id_equipe_domicile CHAR(6) references EQUIPE, +id_equipe_exterieur CHAR(6) references EQUIPE, +Ville VARCHAR2(20), +Categorie char(7) constraint c_type check (Categorie in('Amical','Saison','Playoff','Allstar')), +Score_domicile NUMBER, +Score_exterieur NUMBER, +Prolongation NUMBER); + +CREATE TABLE JOUE(id_joueur CHAR(6) references JOUEUR, +id_game CHAR(6) references GAME, +Points NUMBER, +Rebonds NUMBER, +Interceptions NUMBER, +Contres NUMBER, +Passes NUMBER, +Balles_perdues NUMBER, +Fautes NUMBER, +PRIMARY KEY(id_joueur,id_game)); + + +CREATE TABLE APPARTIENT(id_contrat CHAR(6) PRIMARY KEY, +id_joueur CHAR(6) references JOUEUR, +id_equipe CHAR(6) references EQUIPE, +Date_debut DATE, +Date_fin DATE, +Salaire_jour NUMBER); +\end{verbatim} +\newpage + +\subsection*{HOPITAL} + +\begin{verbatim} + +CREATE TABLE FONCTION(id_fonction CHAR(6) PRIMARY KEY, +Designation VARCHAR(20), +Salaire NUMBER); + +CREATE TABLE HOPITAL(id_hopital CHAR(6) PRIMARY KEY, +Nom VARCHAR(20), +Ville VARCHAR(20), +Date_creation DATE); + + +CREATE TABLE PATIENT(id_patient CHAR(6) PRIMARY KEY, +Nom VARCHAR(20), +Prenom VARCHAR(20), +Date_naissance DATE); + +CREATE TABLE PERSONNEL(id_personnel CHAR(6) PRIMARY KEY, +id_fonction CHAR(6) references FONCTION, +id_hopital CHAR(6) references HOPITAL, +Nom VARCHAR(20), +Prenom VARCHAR(20)); + + +CREATE TABLE AFFECTATION(id_contrat CHAR(6) PRIMARY KEY, +id_personnel CHAR(6) references PERSONNEL, +id_patient CHAR(6) references PATIENT, +Date_debut DATE, +Date_fin DATE); +\end{verbatim} + + +\end{document} diff --git a/EXOS/Exam2019.tex b/EXOS/Exam2019.tex new file mode 100644 index 0000000..300dae7 --- /dev/null +++ b/EXOS/Exam2019.tex @@ -0,0 +1,663 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{url} +\usepackage{comment} +\usepackage{fancyhdr}% fancy header +\usepackage{multirow} +\usepackage{slashbox} + +\usepackage{color, colortbl} +\definecolor{Gray}{gray}{0.9} +\usepackage{adjustbox} +\usepackage{slashbox} +%\usepackage{times} +\usepackage{tikz,pgflibraryarrows,pgffor,pgflibrarysnakes} +\usetikzlibrary{decorations.pathreplacing} + +\usepackage{pdfpages} + +\usepackage{fancyvrb} + +\fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries 2018-2019 BD PLS/SQL\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries ~\leftmark } + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{}%\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + +\usepackage{amsmath} +\usepackage{amsthm} + + + +\theoremstyle{definition} +\newtheorem{exercice}{Exercice} + +\pagestyle{monstyle} + +\usepackage{amsmath} +\usepackage{amsthm} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} +\usepackage{setspace} + + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +\cachefalse % version prof +%\cachetrue % version etudiant + + + +\begin{document} + + +\begin{center} + NOM : \hfill Examen \hfill~\\ + PRENOM : \hfill 90 minutes, 75 points \hfill ~\\ + GROUPE : \hfill Aucun document autoris\'e \hfill~\\ + +\end{center} + +\section*{PL/SQL : NBA Statistiques} +Ci-dessous un mod\`ele de la base de donn\'ees de statistiques de la +NBA (National Basketball Association), o\`u PG, SG, SF, PF et C sont +les diff\'erents postes occup\'es par les joueurs sur le terrain. Un +joueur ne peut pas \^etre en activit\'e dans deux \'equipes en m\^eme temps. + +\begin{center} + \begin{tikzpicture}[every node/.style={inner sep=0,outer sep=0}] + +\node (i) at (6,0) {\begin{varwidth}{1.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}CONTRAT\\ +\hline +\underline{id\_contrat}\\ +\#id\_joueur\\ +\#id\_equipe\\ +Date\_debut\\ +Date\_fin\\ +Salaire\_jour\\ \hline +\end{tabular} +\end{varwidth} +}; + + +\node (a) at (0,0) {\begin{varwidth}{2.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}JOUEUR\\ +\hline +\underline{id\_joueur}\\ +Nom\\ +Pénom\\ +Date\_de\_naissance\\ +Taille\\ +Poste('PG','SG','SF','PF','C')\\ +\hline +\end{tabular} +\end{varwidth} +}; + + +\node (f) at (8,-5) {\begin{varwidth}{2.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}Match\\ +\hline +\underline{id\_match}\\ +Date\_match\\ +\#id\_equipe\_domicile\\ +\#id\_equipe\_exterieur\\ +Ville\\ +Categorie(Amical,Saison,Playoff,Allstar)\\ +Score\_domicile\\ +Score\_exterieur\\ +Prolongation\\ +\hline +\end{tabular} +\end{varwidth} +}; + +\node[draw,rectangle] (g) at (0,-5) {\begin{varwidth}{2in} +\begin{tabular}{l} + \rowcolor{Gray}JOUE\\ + \hline + \underline{\#id\_joueur}\\ + \underline{\#id\_match}\\ + Points\\ + Rebonds\\ + Interceptions\\ + Contres\\ + Passes\\ + Balles\_perdues\\ + Fautes\\ +\end{tabular} +\end{varwidth}}; + + + +\node[draw,rectangle] (c) at (11,0) { +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}EQUIPE\\ +\hline +\underline{id\_equipe}\\ +Nom\\ +Ville\\ +Conference('Est','Ouest')\\ +Date\_creation\\ +\hline +\end{tabular} +}; + +\draw[-latex] (i) -- (a); +\draw[-latex] (i) -- (c); +\draw[-latex] (10,-2.6) -- (10.65,-1.5); +\draw[latex-] (c) -- (f); +\draw[latex-] (f) -- (g); +\draw[latex-] (a) -- (g); + + \end{tikzpicture} +\end{center} + +% \newpage + +\begin{exercice}[NBA, PLSQL] (30 points) +Le MLD ci-dessus stocke les donn\'ees des matchs NBA. + +\begin{enumerate} +\item (15 points) \'Ecrire un code PL/SQL qui, pour un + \code{id\_joueur} saisi par l'utilisateur, liste dans une table + \code{TLIGNES} son maximum de points lors d'un match de sa + carri\`ere. La solution propos\'ee doit mettre en place deux + m\'ecanismes un avec et un sans \code{EXCEPTION} pour traiter les + cas d'erreurs suivants : + \begin{itemize} + \item \code{'joueur inconnu'}, il n'y a pas le joueur dans la table \code{JOUEUR}, + \item \code{'joueur n a pas fait de match'}, il n'apparait pas + dans la table \code{JOUE}. + \end{itemize} + +\begin{SaveVerbatim}{Maxpoints} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off; set verify off; set feedback off; + +variable vidjoueur char(4) +prompt Entrer la reference du joueur : +accept vidjoueur + +DECLARE +dmaxpoint number; +dnbjoueur number; +didjoueur char(4); + +BEGIN +SELECT count(Nom) INTO dnbjoueur FROM JOUEUR WHERE id_joueur ='&vidjoueur'; + +if dnbjoueur != 0 then + +SELECT max(points) INTO dmaxpoint FROM JOUE +WHERE id_joueur ='&vidjoueur'; + +INSERT INTO tligne VALUES ('Max points de'||'&vidjoueur'||' : '||to_char(dmaxpoint)); +ELSE +INSERT INTO tligne VALUES('count detecte numero du joueur pas bon'); + +SELECT id_joueur INTO didjoueur FROM JOUEUR +WHERE id_joueur ='&vidjoueur'; +end if; + +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES('exception numero du joueur pas bon'); +end ; +. +/ + +SELECT * FROM tligne ; +set verify on; set feedback on; set echo on; +\end{SaveVerbatim} + +%% \cache{%\begin{small} +%% \BUseVerbatim{Maxpoints} +%% % \end{small} +%} + + +\item (15 points) \'Ecrire un code PL/SQL qui liste dans une table + \code{TLIGNES} les joueurs en activit\'e (ayant une date de fin de + contrat non nulle) du plus vieux au plus jeune. + +\begin{center} +\begin{verbatim} + Nom Prenom Date de naissance Nom Equipe Actuelle + XXXXXX XXXXXXX XX/XX/XXXX XXXXXXXX + XXXXXX XXXXXXX XX/XX/XXXX XXXXXXXX + XXXXXX XXXXXXX XX/XX/XXXX XXXXXXXX + ... +\end{verbatim} +\end{center} + +\begin{SaveVerbatim}{Joueur} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off; +set verify off; +set feedback off; + +DECLARE +dnom varchar2(20); +dprenom varchar2(20); +ddate date; +dnomequipe varchar2(20); + +CURSOR c IS SELECT j.Nom, j.Prenom, j.Date_de_naissance, e.Nom FROM JOUEUR j, APPARTIENT a, EQUIPE e +WHERE a.id_joueur = j.id_joueur and e.id_equipe = a.id_equipe and a.Date_fin is NULL +Order by Date_de_naissance; + +BEGIN +OPEN c; + +INSERT INTO tligne VALUES ('Nom Prenom Date de naissance Nom Equipe Actuelle'); +FETCH c INTO dnom, dprenom, ddate, dnomequipe; + +WHILE c%found +LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||to_char(ddate)||' '||dnomequipe); + FETCH c INTO dnom, dprenom, ddate, dnomequipe; +END LOOP; + +CLOSE C; +END; +. +/ + +SELECT * FROM tligne ; +set verify on; +set feedback on; +set echo on; +\end{SaveVerbatim} + +%% \cache{%\begin{small} +%% \BUseVerbatim{Joueur} +%% % \end{small} +%% } + +%% \item (20 points) Lister dans une table \code{TLIGNES} tous les +%% joueurs ayant particip\'e \`a un ALLSTAR de la conf\'erence Est et +%% ceux de la conf\'erence Ouest avec les informations suivantes : +%% \begin{center} +%% \begin{small} +%% \begin{verbatim} +%% ALLSTAR MATCH +%% EQUIPE de l'EST +%% Nom Prenom Poste Equipe Actuelle +%% XXXXXX XXXXXXX XXXXXX XXXXXXXX +%% XXXXXX XXXXXXX XXXXXX XXXXXXXX +%% EQUIPE de l'EST +%% Nom Prenom Poste Equipe Actuelle +%% XXXXXX XXXXXXX XXXXXX XXXXXXXX +%% XXXXXX XXXXXXX XXXXXX XXXXXXXX +%% \end{verbatim} +%% \end{small} +%% \end{center} + + +\begin{SaveVerbatim}{Allstar} +DECLARE +dnom varchar2(20); dprenom varchar2(20); +dposte char(2); dnomequipe varchar2(20); + +CURSOR Cest IS SELECT j.Nom, j.Prenom, j.Poste, e.Nom FROM JOUEUR j, +APPARTIENT a, EQUIPE e WHERE a.id_joueur = j.id_joueur and e.id_equipe += a.id_equipe and e.conference='Est' and j.id_joueur in (SELECT +id_joueur FROM JOUE je, GAME g where g.Categorie='Allstar' and +g.id_game=je.id_game); + +CURSOR Couest IS SELECT j.Nom, j.Prenom, j.Poste, e.Nom FROM JOUEUR j, +APPARTIENT a, EQUIPE e WHERE a.id_joueur = j.id_joueur and e.id_equipe += a.id_equipe and e.conference='Ouest' and j.id_joueur in (SELECT +id_joueur FROM JOUE je, GAME g where g.Categorie='Allstar' and +g.id_game=je.id_game); + +BEGIN +INSERT INTO tligne VALUES ('ALLSTAR GAME); +INSERT INTO tligne VALUES ('Conference Est'); +INSERT INTO tligne VALUES ('Nom Prenom Poste Nom Equipe Actuelle'); +OPEN Cest; +FETCH Cest INTO dnom, dprenom, dposte, dnomequipe; +WHILE Cest%found LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||dposte||' '||dnomequipe); + FETCH Cest INTO dnom, dprenom, dposte, dnomequipe; +END LOOP; +CLOSE Cest; +INSERT INTO tligne VALUES ('Conference Ouest'); +OPEN Couest; +INSERT INTO tligne VALUES ('Nom Prenom Poste Nom Equipe Actuelle'); +FETCH Couest INTO dnom, dprenom, dposte, dnomequipe; +WHILE Couest%found LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||dposte||' '||dnomequipe); + FETCH Couest INTO dnom, dprenom, dposte, dnomequipe; +END LOOP; +CLOSE Couest; +END; +. +/ +SELECT * FROM tligne ; +\end{SaveVerbatim} + +%% \cache{\begin{footnotesize} +%% \BUseVerbatim{Allstar} +%% \end{footnotesize} +%% } +\end{enumerate} + +\end{exercice} + + + +\begin{center} + \begin{tikzpicture}[every node/.style={inner sep=0,outer sep=0}] + +\node (a) at (5,-4) {\begin{varwidth}{1.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}AFFECTATION\\ +\hline +\underline{id\_contrat}\\ +\#id\_personnel\\ +\#id\_patient\\ +Date\_debut\\ +Date\_fin\\ \hline +\end{tabular} +\end{varwidth} +}; + + +\node (f) at (0,0) {\begin{varwidth}{2.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}FONCTION\\ +\hline +\underline{id\_fonction}\\ +Designation\\ +Salaire\\ +\hline +\end{tabular} +\end{varwidth} +}; + + +\node (p) at (5,0) {\begin{varwidth}{2.5in} +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}PERSONNEL\\ +\hline +\underline{id\_personnel}\\ +\#id\_fonction\\ +\#id\_hopital\\ +Nom\\ +Prenom\\ +\hline +\end{tabular} +\end{varwidth} +}; + +\node[draw,rectangle] (pa) at (0,-4) {\begin{varwidth}{2in} +\begin{tabular}{l} + \rowcolor{Gray}PATIENT\\ + \hline + \underline{id\_patient}\\ + Nom\\ + Prenom\\ + Date\_naissance\\ +\end{tabular} +\end{varwidth}}; + + + +\node[draw,rectangle] (h) at (9,0) { +\begin{tabular}{|l|} +\hline +\rowcolor{Gray}HOPITAL\\ +\hline +\underline{id\_hopital}\\ +Nom\\ +Ville\\ +Date\_creation\\ +\hline +\end{tabular} +}; + +\draw[-latex] (p) -- (f); +\draw[-latex] (p) -- (h); +\draw[latex-] (p) -- (a); +\draw[latex-] (pa) -- (a); + + \end{tikzpicture} +\end{center} + +\begin{exercice}[Pro C] (45 points) + \begin{enumerate} + \item (30 points) En utilisant les curseurs, \'ecrire un programme + Pro C qui permet d'afficher le nom et pr\'enom des membres du + personnel par hopital en indiquant pour chacun le nombre de + patients suivis et par ordre alphab\'etique des pr\'enoms ayant la + forme suivante : \\ + +\begin{SaveVerbatim}{Affichage} +Personnels de l’hopital XXXXX : + 1) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + 2) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + 3) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + ... +Nombre de patients total sur l'hopital : ZZ1 +Nombre de personnels total sur l'hopital : ZZ2 + +Personnels de l’hopital XXXXX : + 1) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + 2) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + 3) Nom : XXXXXX Prenom : XXXXX Salaire: XXXXX Nombre de patients : ZZ + ... +Nombre de patients total sur l'hopital : ZZ1 +Nombre de personnels total sur l'hopital : ZZ2 +... +\end{SaveVerbatim} + +% \cache{%\begin{small} + \BUseVerbatim{Affichage} + %\end{small} + % } + + Sachant que la valeur de \code{salaire} peut ne pas \^etre + renseignée, il faudra donc g\'erer ce cas. + \item (15 points) \'Ecrire un programme Pro C qui permet d'ins\'erer un nouveau + membre du personnel. Les valeurs saisies par l'utilisateurs seront + ins\'er\'ees dans la table \code{PERSONNEL}. + \begin{itemize} + \item V\'erifier que la fonction existe d\'ej\`a ainsi que l'hopital. + \item + V\'erifier aussi que l'\code{id\_personnel} n'existe pas d\'ej\`a, s'il + existe alors afficher les caract\'eristiques du personnel existant. + \end{itemize} + %% \item 'Ecrire un programme Pro C qui permet de renter une nouvelle + %% affectation entre un patient et un membre du pesonnel. V\'erifier + %% que le patient et le personel existent d\'ej\`a. + + \begin{SaveVerbatim}{Insertion} +TODO +\end{SaveVerbatim} + +%% \cache{%\begin{small} +%% \BUseVerbatim{Insertion} +%% % \end{small} +%% } + + \end{enumerate} +\end{exercice} + + + +\section*{Rappels} +Les fonctions \code{connexion}, \code{deconnexion} et \code{sql\_error} +sont rappell\'ees ci-dessous. Elles ne sont pas \`a r\'e\'ecrire sur +vos copies, mais \`a utiliser dans les exercices si besoin. + +\begin{verbatim} +void connexion() +{ VARCHAR uid[50]; + char login[20]; + char passwd[20]; + printf("Donner votre login : "); + scanf("%s",login); + printf("\nDonnez votre mot de passe Oracle : "); + scanf("%s",passwd); + printf("\n"); + strcpy(uid.arr,login); + strcat(uid.arr,"/"); + strcat(uid.arr,passwd); + strcat(uid.arr,"@kirov"); + uid.len=strlen(uid.arr); + + EXEC SQL CONNECT :uid; + if (sqlca.sqlcode==0) + printf(" Connexion réussie avec succès.\n\n"); + else + { + printf ("Problème à la connexion.\n\n"); + exit(1); + }} +\end{verbatim} + + +\begin{verbatim} +void deconnexion(int validation) +{ + if (validation == 1) + { EXEC SQL COMMIT WORK RELEASE; + } else + { EXEC SQL ROLLBACK WORK RELEASE;} + printf("Déconnexion sans problème.\n"); +} +\end{verbatim} + +\begin{verbatim} +void sql_error(char *msg) +{ char err_msg[128]; + long buf_len, msg_len; + + EXEC SQL WHENEVER SQLERROR CONTINUE; + + printf("%s\n", msg); + buf_len = sizeof (err_msg); + sqlglm(err_msg, &buf_len, &msg_len); + + if (msg_len > buf_len) + msg_len = buf_len; + + printf("%.*s\n", msg_len, err_msg); + deconnexion(0); + exit(1); +} +\end{verbatim} + + +\section*{MEMO} +\subsection*{Langage PL/SQL} + +\begin{verbatim} +DECLARE + variable_PL/SQL {type SQL | nom_table.nom_colonne%TYPE | nom_table%ROWTYPE} ; + CURSOR curseur IS SELECT … ; + nom_exception EXCEPTION; +BEGIN + OPEN curseur ; + FETCH curseur INTO liste de variables ; + curseur%FOUND + CLOSE curseur ; + RAISE nom_exception ; + SELECT liste_de_sélection INTO liste de variables FROM … WHERE … ORDER BY ... ; + Variable PL/SQL := ‘&variable_ SQLPlus’ … + IF … THEN … [ELSE …] END IF ; + WHILE … LOOP … END LOOP ; +EXCEPTION + WHEN nom_exception THEN …; + WHEN NO_DATA_FOUND THEN … ; + WHEN OTHERS THEN … : +END ; +\end{verbatim} + +\subsection*{Langage PRO*C} +\begin{verbatim} +struct {long sqlcode;/* code resultant de l'exécution + =0 -> ok, + >0 -> ok avec un code d'état, + <0 -> erreur */ + struct { + unsigned short sqlerrml;/*longueur du message*/ + char sqlerrmc[70];/*message d'erreur*/ + } sqlerrm; + long sqlerrd[6];/* seul sqlerrd[2] est utilisé -> donne le nombre de lignes modifiées + UPDATE ou rajoutées par INSERT ou ramenées par un SELECT*/ + char sqlwarn[8];/*sqlwarn[0] 'W’ -> warning*/ + sqlwarn[0] = '' /*-> pas de warning*/ + sqlwarn[1] = 'W'/*-> troncation numérique ou char*/ + sqlwarn[2] = 'W'/*-> valeur Null est ignore */ + sqlwarn[3] = 'W'/*-> plus de champs dans SELECT que de variables pour recevoir*/ + sqlwarn[4] = 'W'/*-> toutes les lignes d'une table sont touchées (par DELETE ou + UPDATE par exemple)*/ + sqlwarn[5] /* inutilisé */ + sqlwarn[6] = 'W'/*-> Oracle a dû exécuter un rollback */ + sqlwarn[7] = 'W'/*-> la donnée ramenée par un FETCH a été modifié + depuis que la clause SELECT a été executé */ +} sqlca; +:var_hote INDICATOR :indicateur +:var_hote :indicateur +\end{verbatim} + +%\includepdf[pages=-]{MEMO.pdf} + +\end{document} diff --git a/EXOS/Partiel2019.tex b/EXOS/Partiel2019.tex new file mode 100644 index 0000000..84a28fe --- /dev/null +++ b/EXOS/Partiel2019.tex @@ -0,0 +1,288 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{url} +\usepackage{comment} +\usepackage{fancyhdr}% fancy header +\usepackage{adjustbox} +\usepackage{slashbox} +%\usepackage{times} + +\usepackage{fancyvrb} + +\fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries 2018-2019 BD PLS/SQL\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries ~\leftmark } + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{}%\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + +\usepackage{amsmath} +\usepackage{amsthm} + + + +\theoremstyle{definition} +\newtheorem{exercice}{Exercice} + +\pagestyle{monstyle} + +\usepackage{amsmath} +\usepackage{amsthm} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} +\usepackage{setspace} + + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +%\cachefalse % version prof +\cachetrue % version etudiant + + + +\begin{document} + + +\begin{center} + NOM : \hfill Partiel \hfill~\\ + PRENOM : \hfill 90 minutes, 75 points \hfill ~\\ + GROUPE : \hfill Aucun document autoris\'e \hfill~\\ + +\end{center} + +\begin{exercice}D\'efinitions (15 points) + \begin{enumerate} + \item (3 points) Expliquer ce qu'est une exception. + \cache{Une exception permet de r\'ealiser un traitement lors + qu'une erreur SQL se produit.} + \item (4 points) Donner un exemple d'utilisation de l'exception + \verb+NO_DATA_FOUND+. + \newsavebox\avecalter + \begin{lrbox}{\avecalter} + \begin{minipage}{\textwidth} +\begin{verbatim} +Declare +begin +Select nom into dnom FROM ELEVE Where age < 0; +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES(TO_CHAR(SQLCODE)||' '||SQLERRM||'Age negatif') ; +End; +. +/ +\end{verbatim} + \end{minipage} +\end{lrbox} + \cache{\usebox\avecalter} + + \item (2+2+4=8 points) Donner un exemple simple qui n’est pas possible de + traiter sans un curseur, expliquer pourquoi et montrer comment + créer un curseur et comment l'utiliser dans ce cas là. + + \begin{SaveVerbatim}{VerbEnv} +Declare +dnom Etudaint.nom%TYPE ; +Cursor r is Select nom from Etudiant FOR UPDATE; +BEGIN +OPEN r ; +FETCH r INTO dnom ; +WHILE r%FOUND +LOOP + UPDATE Etudiant SET nom=dnom||'old' WHERE CURRENT of r ; + FETCH r INTO dnom ; +END LOOP ; +COMMIT; +CLOSE R ; +END ; + \end{SaveVerbatim} + \cache{\code{Select nom into dnom from Etudiant ;} + + ici la liste des noms ne va pas pouvoir rentrer dans dnom. + + Il faut donc utiliser un cureur : +\BUseVerbatim{VerbEnv} + +} \end{enumerate} +\end{exercice} + +\newpage + +\begin{exercice}[Soldes] (20 points) +Afin de préparer les soldes d’hiver, écrivez un fichier de commandes +SQL qui, pour un produit saisi par l’utilisateur, si le stock est plus +grand que 100 alors le prix est diminué de 10\% et si le stock plus +grand que 200 alors le prix est diminué de 20\%. Enfin si le stock est +vide alors ajouter dans la table \code{Tligne} une phrase pour +indiquer qu’il faut recommander ce produit en donnant son numéro de +produit. +\end{exercice} + +\begin{SaveVerbatim}{VerbSolde} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; +set echo off ; set verify off ; set feed off; + +variable vnoproduit char(4) +prompt Entrer la reference du fournisseur : +accept vnoproduit + +DECLARE +dstock number; + +BEGIN +SELECT count(stock) INTO dstock +FROM Tproduit +Where noproduit=’&vnoproduit’; + +If dstock = 0 then + INSERT INTO tligne VLAUES (‘Stock Null pour ce produit + ’||’&vnoporduit’||’Recommander ’) ; + End if; +If dstock >200 then + UPDATE Tproduit SET prixv=dprix*1.2 WHERE noproduit=’&vnoproduit’; + Else If dstock > 100 then + UPDATE Tproduit SET prixv=dprix*1.1 WHERE noproduit=’&vnoproduit’; +End if; +End; +. +/ +SELECT * FROM tligne ; +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} +\cache{%\begin{small} + \BUseVerbatim{VerbSolde} +% \end{small} +} + +\newpage +\begin{exercice}[Fournisseur] (20 points) +Ecrire un fichier de commandes SQL qui demande un numéro de produit et +qui retourne le message ‘le produit n’a pas de fournisseur’ ou ‘le +produit a plusieurs fournisseurs’, ou le 'Nom' du fournisseur s’il +n’en a qu’un. Le résultat sera placé dans une table \code{Tligne + (LIGNE varchar2(200))} et contiendra le message et le code d’erreur +produit par Oracle. +\end{exercice} + +\begin{SaveVerbatim}{Verbfour} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off ; set verify off ; set feed off ; + +variable vreffourn char(4) +prompt Entrer la reference du produit : +accept vnoproduit + +DECLARE +dnomfour char(20) ; +dreffour char(4) + +BEGIN +SELECT refourn INTO dreffour FROM Tproduitfourn +WHERE nopoduit ='&vnoproduit' ; + +SELECT Nom INTO dnomfour FROM TFounisseur +Where ref-fourn='dreffour; + +INSERT INTO tligne VALUES (dnomfour) ; + +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES(TO_CHAR(SQLCODE)||' '||SQLERRM||' Le produit +n''a pas de fournisseur' ) ; +when too_many_rows then +INSERT INTO tligne VALUES(O_CHAR(SQLCODE)||' '||SQLERRM||' Le produit a +plusieurs fournieeurs) ; +End ; +. +/ +SELECT * FROM tligne ; +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} + +\cache{%\begin{small} + \BUseVerbatim{Verbfour} +% \end{small} +} + +\newpage +\begin{exercice}[Curseur] (20 points) +Ecrivez un fichier de commandes SQL qui diminue de 10\% les prix des +produits qui ont un stock de plus de 500. +\end{exercice} +\begin{SaveVerbatim}{Verbcinq} +set echo off ; set verify off ; set feed off ; + +Declare +dprix Tproduit.prix%TYPE ; + +CURSOR r IS SELECT prixv FROM Tproduit WHERE Tproduit.stock >500 +FOR UPDATE ; + +BEGIN +OPEN r ; +FETCH r INTO dprix ; +WHILE r%FOUND +LOOP +UPDATE Tproduit SET prixv=dprix*1.1 WHERE CURRENT of r ; + FETCH r INTO dprix ; +END LOOP ; +COMMIT ; +CLOSE R ; +END ; +. +/ +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} +\cache{%\begin{small} + \BUseVerbatim{Verbcinq} +% \end{small} +} + +%\newpage + +\section*{Rappel} + \begin{center} + \includegraphics[width=14cm]{BD.png} + \end{center} + +\end{document} diff --git a/EXOS/Partiel2020.tex b/EXOS/Partiel2020.tex new file mode 100644 index 0000000..84a28fe --- /dev/null +++ b/EXOS/Partiel2020.tex @@ -0,0 +1,288 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[french]{babel} +\usepackage[a4paper,hmargin=20mm,vmargin=30mm]{geometry}%\usepackage{fullpage} +\usepackage{url} +\usepackage{comment} +\usepackage{fancyhdr}% fancy header +\usepackage{adjustbox} +\usepackage{slashbox} +%\usepackage{times} + +\usepackage{fancyvrb} + +\fancypagestyle{monstyle}{ +%\fancyhead{} +\renewcommand{\headrulewidth}{1pt} +%% %\renewcommand{\footrulewidth}{0.4pt} + +% \fancyhead[LE]{\slshape \thepage/ \pageref{LastPage}} +%% \fancyhead[RO]{\slshape \thepage/ \pageref{LastPage}} + + +%\fancyhf{} +%\fancyhead[LE]{\slshape LE} +%\fancyhead[CE]{\slshape CE} +%\fancyhead[RE]{\slshape RE} + +\fancyhead[LO]{\bfseries 2018-2019 BD PLS/SQL\rightmark} +%\fancyhead[CO]{\slshape APF} +\fancyhead[RO]{\bfseries ~\leftmark } + +%% %\fancyfoot{} +% \fancyfoot[LE,RO]{} + \fancyfoot[CO,CE]{}%\slshape\thepage/\pageref{LastPage}} +%% %\fancyfoot[LO,RE]{\small\slshape \ddmmyyyydate version du \today} + +} + +% \pagestyle{fancy} + +\usepackage{amsmath} +\usepackage{amsthm} + + + +\theoremstyle{definition} +\newtheorem{exercice}{Exercice} + +\pagestyle{monstyle} + +\usepackage{amsmath} +\usepackage{amsthm} + +\newcommand{\code}[1]{\texttt{#1}} + +\usepackage{boxedminipage} +\usepackage{setspace} + + +\newsavebox\svbx +\newif\ifcache +\long\def\cache#1{\ \newline + \setbox\svbx=\vbox{\leavevmode \newline \begin{spacing}{1}#1\end{spacing}} + \smallskip\par\noindent + \begin{boxedminipage}{\linewidth} + \ifcache + \leavevmode\hrule height 0pt\vskip \ht\svbx\hrule height 0pt + \else \unvbox\svbx + \fi + \end{boxedminipage} + \par\smallskip} + + +%\cachefalse % version prof +\cachetrue % version etudiant + + + +\begin{document} + + +\begin{center} + NOM : \hfill Partiel \hfill~\\ + PRENOM : \hfill 90 minutes, 75 points \hfill ~\\ + GROUPE : \hfill Aucun document autoris\'e \hfill~\\ + +\end{center} + +\begin{exercice}D\'efinitions (15 points) + \begin{enumerate} + \item (3 points) Expliquer ce qu'est une exception. + \cache{Une exception permet de r\'ealiser un traitement lors + qu'une erreur SQL se produit.} + \item (4 points) Donner un exemple d'utilisation de l'exception + \verb+NO_DATA_FOUND+. + \newsavebox\avecalter + \begin{lrbox}{\avecalter} + \begin{minipage}{\textwidth} +\begin{verbatim} +Declare +begin +Select nom into dnom FROM ELEVE Where age < 0; +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES(TO_CHAR(SQLCODE)||' '||SQLERRM||'Age negatif') ; +End; +. +/ +\end{verbatim} + \end{minipage} +\end{lrbox} + \cache{\usebox\avecalter} + + \item (2+2+4=8 points) Donner un exemple simple qui n’est pas possible de + traiter sans un curseur, expliquer pourquoi et montrer comment + créer un curseur et comment l'utiliser dans ce cas là. + + \begin{SaveVerbatim}{VerbEnv} +Declare +dnom Etudaint.nom%TYPE ; +Cursor r is Select nom from Etudiant FOR UPDATE; +BEGIN +OPEN r ; +FETCH r INTO dnom ; +WHILE r%FOUND +LOOP + UPDATE Etudiant SET nom=dnom||'old' WHERE CURRENT of r ; + FETCH r INTO dnom ; +END LOOP ; +COMMIT; +CLOSE R ; +END ; + \end{SaveVerbatim} + \cache{\code{Select nom into dnom from Etudiant ;} + + ici la liste des noms ne va pas pouvoir rentrer dans dnom. + + Il faut donc utiliser un cureur : +\BUseVerbatim{VerbEnv} + +} \end{enumerate} +\end{exercice} + +\newpage + +\begin{exercice}[Soldes] (20 points) +Afin de préparer les soldes d’hiver, écrivez un fichier de commandes +SQL qui, pour un produit saisi par l’utilisateur, si le stock est plus +grand que 100 alors le prix est diminué de 10\% et si le stock plus +grand que 200 alors le prix est diminué de 20\%. Enfin si le stock est +vide alors ajouter dans la table \code{Tligne} une phrase pour +indiquer qu’il faut recommander ce produit en donnant son numéro de +produit. +\end{exercice} + +\begin{SaveVerbatim}{VerbSolde} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; +set echo off ; set verify off ; set feed off; + +variable vnoproduit char(4) +prompt Entrer la reference du fournisseur : +accept vnoproduit + +DECLARE +dstock number; + +BEGIN +SELECT count(stock) INTO dstock +FROM Tproduit +Where noproduit=’&vnoproduit’; + +If dstock = 0 then + INSERT INTO tligne VLAUES (‘Stock Null pour ce produit + ’||’&vnoporduit’||’Recommander ’) ; + End if; +If dstock >200 then + UPDATE Tproduit SET prixv=dprix*1.2 WHERE noproduit=’&vnoproduit’; + Else If dstock > 100 then + UPDATE Tproduit SET prixv=dprix*1.1 WHERE noproduit=’&vnoproduit’; +End if; +End; +. +/ +SELECT * FROM tligne ; +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} +\cache{%\begin{small} + \BUseVerbatim{VerbSolde} +% \end{small} +} + +\newpage +\begin{exercice}[Fournisseur] (20 points) +Ecrire un fichier de commandes SQL qui demande un numéro de produit et +qui retourne le message ‘le produit n’a pas de fournisseur’ ou ‘le +produit a plusieurs fournisseurs’, ou le 'Nom' du fournisseur s’il +n’en a qu’un. Le résultat sera placé dans une table \code{Tligne + (LIGNE varchar2(200))} et contiendra le message et le code d’erreur +produit par Oracle. +\end{exercice} + +\begin{SaveVerbatim}{Verbfour} +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off ; set verify off ; set feed off ; + +variable vreffourn char(4) +prompt Entrer la reference du produit : +accept vnoproduit + +DECLARE +dnomfour char(20) ; +dreffour char(4) + +BEGIN +SELECT refourn INTO dreffour FROM Tproduitfourn +WHERE nopoduit ='&vnoproduit' ; + +SELECT Nom INTO dnomfour FROM TFounisseur +Where ref-fourn='dreffour; + +INSERT INTO tligne VALUES (dnomfour) ; + +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES(TO_CHAR(SQLCODE)||' '||SQLERRM||' Le produit +n''a pas de fournisseur' ) ; +when too_many_rows then +INSERT INTO tligne VALUES(O_CHAR(SQLCODE)||' '||SQLERRM||' Le produit a +plusieurs fournieeurs) ; +End ; +. +/ +SELECT * FROM tligne ; +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} + +\cache{%\begin{small} + \BUseVerbatim{Verbfour} +% \end{small} +} + +\newpage +\begin{exercice}[Curseur] (20 points) +Ecrivez un fichier de commandes SQL qui diminue de 10\% les prix des +produits qui ont un stock de plus de 500. +\end{exercice} +\begin{SaveVerbatim}{Verbcinq} +set echo off ; set verify off ; set feed off ; + +Declare +dprix Tproduit.prix%TYPE ; + +CURSOR r IS SELECT prixv FROM Tproduit WHERE Tproduit.stock >500 +FOR UPDATE ; + +BEGIN +OPEN r ; +FETCH r INTO dprix ; +WHILE r%FOUND +LOOP +UPDATE Tproduit SET prixv=dprix*1.1 WHERE CURRENT of r ; + FETCH r INTO dprix ; +END LOOP ; +COMMIT ; +CLOSE R ; +END ; +. +/ +set verify on ; set feed on ; set echo on ; +\end{SaveVerbatim} +\cache{%\begin{small} + \BUseVerbatim{Verbcinq} +% \end{small} +} + +%\newpage + +\section*{Rappel} + \begin{center} + \includegraphics[width=14cm]{BD.png} + \end{center} + +\end{document} diff --git a/EXOS/hopital-setup.sql b/EXOS/hopital-setup.sql new file mode 100644 index 0000000..ff6c0bd --- /dev/null +++ b/EXOS/hopital-setup.sql @@ -0,0 +1,68 @@ +DROP TABLE PERSONNEL cascade constraints; +DROP TABLE AFFECTATION ; + +DROP TABLE FONCTION cascade constraints; +DROP TABLE PATIENT cascade constraints; +DROP TABLE HOPITAL cascade constraints; + +CREATE TABLE FONCTION(id_fonction CHAR(6) PRIMARY KEY, +Designation VARCHAR(20), +Salaire NUMBER); + +CREATE TABLE HOPITAL(id_hopital CHAR(6) PRIMARY KEY, +Nom VARCHAR(20), +Ville VARCHAR(20), +Date_creation DATE); + + +CREATE TABLE PATIENT(id_patient CHAR(6) PRIMARY KEY, +Nom VARCHAR(20), +Prenom VARCHAR(20), +Date_naissance DATE); + +CREATE TABLE PERSONNEL(id_personnel CHAR(6) PRIMARY KEY, +id_fonction CHAR(6) references FONCTION, +id_hopital CHAR(6) references HOPITAL, +Nom VARCHAR(20), +Prenom VARCHAR(20)); + + +CREATE TABLE AFFECTATION(id_contrat CHAR(6) PRIMARY KEY, +id_personnel CHAR(6) references PERSONNEL, +id_patient CHAR(6) references PATIENT, +Date_debut DATE, +Date_fin DATE); + +insert into HOPITAL values ('H01','CHU G MONPIED','CLERMONT','01-Jan-1980'); +insert into HOPITAL values ('H02','CHU ESTAING','CLERMONT','01-Jan-2010'); +insert into HOPITAL values ('H03','Chataigneraie','BEAUMONT','01-Jan-2000'); + +insert into FONCTION values ('F01','Docteur',8000); +insert into FONCTION values ('F02','Psy',11000); +insert into FONCTION values ('F03','ORL',10000); + +insert into PERSONNEL values ('PE01','F03','H03','Who','John'); +insert into PERSONNEL values ('PE02','F02','H01','Jekyll','Henry'); +insert into PERSONNEL values ('PE03','F01','H02','Watson','James'); +insert into PERSONNEL values ('PE04','F02','H03','Palmer','Jimmy'); +insert into PERSONNEL values ('PE05','F01','H01','Mallard','Donald'); +insert into PERSONNEL values ('PE06','F03','H02','Blacke','Penelope'); + +insert into PATIENT values ('PA01','Marley','Bob','04-Apr-2001'); +insert into PATIENT values ('PA02','Hendrix','Jimmy','04-Apr-1998'); +insert into PATIENT values ('PA03','Dupont','Paul','04-Apr-1990'); +insert into PATIENT values ('PA04','Springsteen','Bruce','24-Apr-1990'); +insert into PATIENT values ('PA05','Jackson','Michael','14-Apr-1990'); +insert into PATIENT values ('PA06','Georges','Paul','04-Apr-1991'); + +insert into AFFECTATION values ('A01','PE01','PA01','04-Jan-1980',NULL); +insert into AFFECTATION values ('A02','PE02','PA02','04-Jan-1981',NULL); +insert into AFFECTATION values ('A03','PE03','PA03','04-Jan-1981','04-Jan-2010'); +insert into AFFECTATION values ('A04','PE04','PA04','04-Jan-1981','04-Jan-2010'); +insert into AFFECTATION values ('A05','PE05','PA05','04-Jan-1981','04-Jan-2010'); +insert into AFFECTATION values ('A06','PE06','PA06','04-Jan-1981','04-Jan-2010'); + + + + + diff --git a/EXOS/nba-q1.sql b/EXOS/nba-q1.sql new file mode 100644 index 0000000..e6b1e9a --- /dev/null +++ b/EXOS/nba-q1.sql @@ -0,0 +1,48 @@ +@nba-setup.sql; + +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off; +set verify off; +set feedback off; + +variable vidjoueur char(4) +prompt Entrer la reference du joueur : +accept vidjoueur + +DECLARE +dmaxpoint number; +dnbjoueur number; +didjoueur char(4); + +BEGIN + +SELECT count(Nom) INTO dnbjoueur FROM JOUEUR +WHERE id_joueur ='&vidjoueur'; + +if dnbjoueur != 0 then + +SELECT max(points) INTO dmaxpoint FROM JOUE +WHERE id_joueur ='&vidjoueur'; + +INSERT INTO tligne VALUES ('Le maximum de point du joueur '||'&vidjoueur'||' est '||to_char(dmaxpoint)); +ELSE +INSERT INTO tligne VALUES('AVEC COUNT : Joueur inconnu'); +end if; + +SELECT id_joueur INTO didjoueur FROM JOUE +WHERE id_joueur ='&vidjoueur'; + + +EXCEPTION +when no_data_found then +INSERT INTO tligne VALUES('AVEC EXCEPTION : Joueur n a pas fait de match'); +end ; +. +/ + +SELECT * FROM tligne ; +set verify on; +set feedback on; +set echo on; diff --git a/EXOS/nba-q2.sql b/EXOS/nba-q2.sql new file mode 100644 index 0000000..f4b44a2 --- /dev/null +++ b/EXOS/nba-q2.sql @@ -0,0 +1,41 @@ +@nba-setup.sql; + +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off; +set verify off; +set feedback off; + +DECLARE +dnom varchar2(20); +dprenom varchar2(20); +ddate date; +dnomequipe varchar2(20); + +CURSOR c IS SELECT j.Nom, j.Prenom, j.Date_de_naissance, e.Nom FROM JOUEUR j, APPARTIENT a, EQUIPE e +WHERE a.id_joueur = j.id_joueur and e.id_equipe = a.id_equipe and a.Date_fin is NULL +Order by Date_de_naissance; + + +BEGIN +OPEN c; + +INSERT INTO tligne VALUES ('Nom Prenom Date de naissance Nom Equipe Actuelle'); +FETCH c INTO dnom, dprenom, ddate, dnomequipe; + +WHILE c%found +LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||to_char(ddate)||' '||dnomequipe); + FETCH c INTO dnom, dprenom, ddate, dnomequipe; +END LOOP; + +CLOSE C; +END; +. +/ + +SELECT * FROM tligne ; +set verify on; +set feedback on; +set echo on; diff --git a/EXOS/nba-q3.sql b/EXOS/nba-q3.sql new file mode 100644 index 0000000..c7c5c7e --- /dev/null +++ b/EXOS/nba-q3.sql @@ -0,0 +1,72 @@ +@nba-setup.sql; + +DROP TABLE tligne ; +CREATE TABLE tligne (ligne varchar2(100)) ; + +set echo off; +set verify off; +set feedback off; + +variable vannee number +prompt Entrer une annee : +accept vannee + +DECLARE +dnom varchar2(20); +dprenom varchar2(20); +dposte char(2); +dnomequipe varchar2(20); + +CURSOR Cest IS SELECT j.Nom, j.Prenom, j.Poste, e.Nom FROM JOUEUR j, +APPARTIENT a, EQUIPE e WHERE a.id_joueur = j.id_joueur and e.id_equipe += a.id_equipe and e.conference='Est' and j.id_joueur in (SELECT +id_joueur FROM JOUE je, GAME g where g.Categorie='Allstar' and +g.id_game=je.id_game); + +CURSOR Couest IS SELECT j.Nom, j.Prenom, j.Poste, e.Nom FROM JOUEUR j, +APPARTIENT a, EQUIPE e WHERE a.id_joueur = j.id_joueur and e.id_equipe += a.id_equipe and e.conference='Ouest' and j.id_joueur in (SELECT +id_joueur FROM JOUE je, GAME g where g.Categorie='Allstar' and +g.id_game=je.id_game); + +BEGIN + +INSERT INTO tligne VALUES ('ALLSTAR GAME'||'&vannee'); +INSERT INTO tligne VALUES ('Conference Est'); + +OPEN Cest; + +INSERT INTO tligne VALUES ('Nom Prenom Poste Nom Equipe Actuelle'); +FETCH Cest INTO dnom, dprenom, dposte, dnomequipe; + +WHILE Cest%found +LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||dposte||' '||dnomequipe); + FETCH Cest INTO dnom, dprenom, dposte, dnomequipe; +END LOOP; + +CLOSE Cest; + +INSERT INTO tligne VALUES ('Conference Ouest'); + +OPEN Couest; + +INSERT INTO tligne VALUES ('Nom Prenom Poste Nom Equipe Actuelle'); + +FETCH Couest INTO dnom, dprenom, dposte, dnomequipe; +WHILE Couest%found +LOOP + INSERT INTO tligne VALUES (dnom||' '||dprenom||' '||dposte||' '||dnomequipe); + FETCH Couest INTO dnom, dprenom, dposte, dnomequipe; +END LOOP; + +CLOSE Couest; + +END; +. +/ + +SELECT * FROM tligne ; +set verify on; +set feedback on; +set echo on; diff --git a/EXOS/nba-setup.sql b/EXOS/nba-setup.sql new file mode 100644 index 0000000..d194e06 --- /dev/null +++ b/EXOS/nba-setup.sql @@ -0,0 +1,88 @@ +DROP TABLE JOUE; +DROP TABLE GAME; +DROP TABLE APPARTIENT cascade constraints; +DROP TABLE JOUEUR cascade constraints; +DROP TABLE EQUIPE cascade constraints; + +CREATE TABLE JOUEUR(id_joueur CHAR(6) PRIMARY KEY, +Nom VARCHAR2(20), +Prenom VARCHAR2(20), +Date_de_naissance DATE, +Taille NUMBER, +Poste char(2) constraint c_poste CHECK (Poste IN('PG','SG','SF','PF','C'))); + +CREATE TABLE EQUIPE(id_equipe CHAR(6) PRIMARY KEY, +Nom VARCHAR2(20), +Ville VARCHAR2(20), +Conference VARCHAR2(5) constraint c_conf check (Conference in('Est','Ouest')), +Date_creation DATE); + +CREATE TABLE GAME(id_game CHAR(6) PRIMARY KEY, +Date_game DATE, +id_equipe_domicile CHAR(6) references EQUIPE, +id_equipe_exterieur CHAR(6) references EQUIPE, +Ville VARCHAR2(20), +Categorie char(7) constraint c_type check (Categorie in('Amical','Saison','Playoff','Allstar')), +Score_domicile NUMBER, +Score_exterieur NUMBER, +Prolongation NUMBER); + +CREATE TABLE JOUE(id_joueur CHAR(6) references JOUEUR, +id_game CHAR(6) references GAME, +Points NUMBER, +Rebonds NUMBER, +Interceptions NUMBER, +Contres NUMBER, +Passes NUMBER, +Balles_perdues NUMBER, +Fautes NUMBER, +PRIMARY KEY(id_joueur,id_game)); + + +CREATE TABLE APPARTIENT(id_contrat CHAR(6) PRIMARY KEY, +id_joueur CHAR(6) references JOUEUR, +id_equipe CHAR(6) references EQUIPE, +Date_debut DATE, +Date_fin DATE, +Salaire_jour NUMBER); + +insert into JOUEUR values ('J00001','Jordan','Michael','01-Jan-1980','193','SF'); +insert into JOUEUR values ('J00002','Bird','Larry','02-Jan-1980','194','SF'); +insert into JOUEUR values ('J00003','Johnson','Magic','03-Jan-1980','201','PG'); +insert into JOUEUR values ('J00004','Thomas','Isiah','04-Jan-1980','185','PG'); +insert into JOUEUR values ('J00005','Oneil','Shaquille','04-Jan-1992','185','C'); +insert into JOUEUR values ('J00006','Parker','Tony','04-Jan-1996','185','PG'); + + +insert into EQUIPE values ('E00001','Bulls','Chicago','Est','04-Jan-1970'); +insert into EQUIPE values ('E00002','Lakers','LA','Ouest','06-Jan-1970'); +insert into EQUIPE values ('E00003','Pistons','Detroit','Est','07-Jan-1970'); +insert into EQUIPE values ('E00004','Celtics','Boston','Est','09-Jan-1970'); +insert into EQUIPE values ('E00005','Spurs','San Antonio','Ouest','06-Jan-1971'); + +insert into APPARTIENT values ('C00001','J00001','E00001','04-Jan-1980',NULL,10000); +insert into APPARTIENT values ('C00002','J00002','E00004','04-Jan-1981',NULL,1000); +insert into APPARTIENT values ('C00003','J00003','E00002','04-Jan-1981','04-Jan-2010',3000); +insert into APPARTIENT values ('C00004','J00004','E00003','04-Jan-1982',NULL,5000); +insert into APPARTIENT values ('C00005','J00005','E00002','04-Jan-1990',NULL,5000); +insert into APPARTIENT values ('C00006','J00006','E00005','04-Jan-1990',NULL,5000); + +insert into GAME values ('G00001','04-Jan-2001','E00002','E00001','Londres','Saison',100,101,0); +insert into GAME values ('G00002','04-Jan-2001','E00003','E00004','Boston','Saison',102,101,0); +insert into GAME values ('G00003','04-May-2001','E00004','E00003','Detroit','Playoff',107,101,0); +insert into GAME values ('G00004','04-Apr-2001','E00001','E00002','Miami','Allstar',105,101,0); +insert into GAME values ('G00005','04-Apr-2001','E00001','E00003','Miami','Allstar',105,101,0); +insert into GAME values ('G00006','04-Apr-2001','E00001','E00004','Miami','Allstar',105,101,0); + +insert into JOUE values ('J00006','G00004',17,18,1,0,1,3,4); +insert into JOUE values ('J00005','G00004',17,18,1,0,1,3,4); +insert into JOUE values ('J00002','G00004',17,18,1,0,1,3,4); +insert into JOUE values ('J00003','G00004',17,18,1,0,1,3,4); +insert into JOUE values ('J00001','G00006',17,18,1,0,1,3,4); +insert into JOUE values ('J00003','G00006',17,18,1,0,1,3,4); +insert into JOUE values ('J00003','G00005',17,18,1,0,1,3,4); +insert into JOUE values ('J00004','G00004',17,18,1,0,1,3,4); +insert into JOUE values ('J00001','G00003',20,10,4,1,2,2,3); +insert into JOUE values ('J00001','G00002',19,11,3,2,2,1,2); +insert into JOUE values ('J00001','G00001',18,12,2,3,1,0,1); +