On va dans un premier temps se familiariser avec les requêtes SQL sur des bases de données utilisant le logiciel SQLite. On travaillera sur trois bases :

  • eleves.db : base de données très basique, constituée d’une seule table, décrivant les élèves d’un établissement scolaire.

  • clients.db : base de données décrivant des opérations d’une banque, et constituée de trois tables : client, compte, operation.

  • chinook.db : base de donnée proposée par les concepteurs de SQLite à des fins de tests. Elle est plus complexe et volumineuse que les deux premières.

Ces trois bases se trouvent dans le répertoire /users/partage. Si vous travaillez sur les machines locales, vous n’avez pas besoin de recopier ces données dans votre répertoire.

Elles se trouvent aussi dans le répertoire data pour ceux qui travaillent sur leur propre machine.

On se connectera sur une base par l’utilitaire sqlite3 en ligne de commande en tapant une commande

sqlite3 chemin_vers_base.db

On trouvera de l’aide sur sqlite3 sur la page https://www.sqlite.org/cli.html . Dans l’interface en ligne de commande, on peut entrer :

  • soit des commandes SQL

  • soit des commandes propres à sqlite3, qui sont toutes préfixées par un point : .help ou .quit par exemple.

Par moment, on utilisera aussi l’utilitaire graphique sqlitebrowser.

La base eleves

  1. Ouvrir la base eleves.db avec sqlite3 et regarder combien elle a de tables.

  2. Afficher toutes les lignes de la table classe

  3. Faire afficher les noms et prénoms de tous les élèves nés strictement avant 1996.

  4. Faire afficher les noms et prénoms de tous les élèves ayant anglais en LV1 et allemand en LV2.

  5. Faire afficher tous les élèves étudiant l’anglais et l’allemand.

  6. Faire afficher tous les élèves dont le prénom commence par "J" et finit par "n".

  7. Quittez la base.

La base clients

  1. Explorer la structure de cette base de données.

  2. Quels sont les nom et prénom du client n° 42 ?

  3. Quels sont les nom et prénom (sans doublon) des clients qui possèdent un livret A ?

  4. Etablir un listing des opérations dont le montant est compris entre 0 et 100 euros. Pour chaque opération, on veut le numéro du compte, le type de compte, le montant et l’information de l’opération.

  5. Etablir un listing des des opérations dont le montant est compris entre 0 et 100 euros en affichant les nom et prénom du titulaire du compte, et le montant de l’opération.

  6. Même chose, en se restreigant aux opérations effectuées au guichet et sur un livret A.

  7. Quel est le nombre de livret A ?

  8. Que fait :

SELECT compte.idproprietaire, COUNT(*)
FROM compte
GROUP BY idproprietaire ;
  1. Afficher pour chaque client, identifié par son nom et son prénom, le nombre de comptes qu’il détient.

    • Pour faire la somme des opérations, on peut faire

SELECT SUM(operation.montant)
FROM operation ;

Afficher pour chaque client, identifié par son nom et son prénom, la somme des opérations qu’il effectuées au guichet.

La base chinook

Explorer la base chinook.db et essayez de comprendre son architecture. On reviendra plus loin dessus quand on discutera de la conception des bases de données.

Répondre aux questions suivantes (en anglais, car elle proviennent d’un TP puisé sur internet)

  1. Provide a query showing Customers (just their full names, customer ID and country) who are not in the US.

  2. Provide a query only showing the Customers from Brazil.

  3. Provide a query showing the Invoices of customers who are from Brazil. The resultant table should show the customer’s full name, Invoice ID, Date of the invoice and billing country.

  4. Provide a query showing only the Employees who are Sales Agents.

  5. Provide a query showing a unique list of billing countries from the Invoice table.

  6. Provide a query showing the invoices of customers who are from Brazil.

  7. Provide a query that shows the invoices associated with each sales agent. The resultant table should include the Sales Agent’s full name.

  8. Provide a query that shows the Invoice Total, Customer name, Country and Sale Agent name for all invoices and customers.

  9. How many Invoices were there in 2009 and 2011 ? What are the respective total sales for each of those years ?

  10. Looking at the InvoiceLine table, provide a query that COUNTs the number of line items for Invoice ID 37.

  11. Looking at the InvoiceLine table, provide a query that COUNTs the number of line items for each Invoice. HINT : GROUP BY

  12. Provide a query that includes the track name with each invoice line item.

  13. Provide a query that includes the purchased track name AND artist name with each invoice line item.

  14. Provide a query that shows the number of invoices per country. HINT : GROUP BY

  15. Provide a query that shows the total number of tracks in each playlist. The Playlist name should be include on the resultant table.

  16. Provide a query that shows all the Tracks, but displays no IDs. The resultant table should include the Album name, Media type and Genre.

  17. Provide a query that shows all Invoices but includes the number of invoice line items.

  18. Provide a query that shows total sales made by each sales agent.

  19. Which sales agent made the most in sales in 2009 ?

  20. Which sales agent made the most in sales in 2010 ?

  21. Which sales agent made the most in sales over all ?

  22. Provide a query that shows the number of customers assigned to each sales agent.

  23. Provide a query that shows the total sales per country. Which country’s customers spent the most ?

  24. Provide a query that shows the most purchased track of 2013.

  25. Provide a query that shows the top 5 most purchased tracks over all.

  26. Provide a query that shows the top 3 best selling artists.

  27. Provide a query that shows the most purchased Media Type.

--1 les attributs des clients non aux USA
SELECT FirstName,
    LastName,
    CustomerId,
    Country
FROM customers
WHERE country NOT IN ('USA');

--------------------------------------------------------

--2 les attributs des clients au Brésil
SELECT FirstName,
    LastName,
    CustomerId,
    Country
FROM customers
WHERE country='Brazil';

---------------------------------------------------------

--3 les clients au Brésil et leurs factures
SELECT c.FirstName,
    c.LastName,
    i.InvoiceId,
    i.InvoiceDate,
    i.BillingCountry
FROM customers c
    JOIN invoices i
        ON i.CustomerId=c.CustomerId
            AND c.Country='Brazil';

-- ou bien :
SELECT c.FirstName,
    c.LastName,
    i.InvoiceId,
    i.InvoiceDate,
    i.BillingCountry
FROM customers c
    JOIN invoices i
        ON i.CustomerId=c.CustomerId
WHERE c.Country='Brazil';

-- ou encore
SELECT c.FirstName,
    c.LastName,
    i.InvoiceId,
    i.InvoiceDate,
    i.BillingCountry
FROM customers c, invoices i
WHERE i.CustomerId=c.CustomerId
    AND c.Country='Brazil';

---------------------------------------------------------

--4 les employés du département des ventes
SELECT *
FROM employees
WHERE title LIKE 'Sales%';

---------------------------------------------------------

--5 les différents pays où des factures ont été émises
SELECT distinct BillingCountry
FROM invoices;

---------------------------------------------------------

--6 les clients du Brésil et leurs factures
SELECT *
FROM customers c
	JOIN invoices i
        ON i.CustomerId=c.CustomerId
            AND c.Country='Brazil';

---------------------------------------------------------

--7 Les factures associées à chaque agent commercial.
-- Malheureusement, on ne peut pas utiliser un GROUP BY
-- Tout ce qu'on peut faire est d'ordonner au mieux ...

SELECT e.firstname,
    e.lastname,
    i.*
FROM customer AS c
    JOIN invoices as i
        ON c.customerid = i.customerid
    JOIN employees AS e
        ON e.employeeid = c.supportrepid
ORDER BY e.employeeid;

---------------------------------------------------------

--8 total de facture, nom client, pays, agent commercial  pour tous les (facture+client)


SELECT e.firstname AS 'prenom_employe',
    e.lastname AS 'nom_employe',
    c.firstname AS 'client_prenom',
    c.lastname AS 'client_nom',
    c.country,
    i.total
FROM employees AS e
	JOIN customers AS c
        ON e.employeeid = c.supportrepid
	JOIN invoices AS i
        ON c.customerid = i.customerid

---------------------------------------------------------

--9 How many Invoices were there in 2009 and 2011?
--  What are the respective total sales for each of those years?
SELECT strftime('%Y',InvoiceDate) AS annee ,
	COUNT(*),
	SUM(Total)
FROM invoices
WHERE annee IN ('2009','2011')
GROUP BY annee;

---------------------------------------------------------

--10  Le nombre de lignes de facture pour la facture 37
SELECT COUNT(*)
FROM invoice_items
WHERE InvoiceId=37;

---------------------------------------------------------

--11  le nombre de lignes de factures pour chaque  facture
SELECT InvoiceId,
	COUNT(*)
FROM invoice_items
GROUP BY InvoiceId;

---------------------------------------------------------

--12  Rajouter à chaque ligne de commande, le nom de la piste
SELECT i.*,
	t.Name
FROM invoice_items i
	JOIN tracks t
        ON i.TrackId=t.TrackId
ORDER BY i.InvoiceLineId;

---------------------------------------------------------

--13 Même chose, plus le nom de l'artiste
SELECT i.*,
	t.Name,
	ar.Name
FROM invoice_items i
	JOIN tracks t
        on i.TrackId=t.TrackId
    JOIN albums a
        ON t.AlbumId=a.albumId
    JOIN artists ar
        ON a.ArtistId=ar.ArtistId
ORDER BY i.InvoiceLineId;

---------------------------------------------------------

--14  Le nombre de factures par pays
SELECT BillingCountry ,
	COUNT(*)
FROM invoices
GROUP BY BillingCountry;

---------------------------------------------------------

--15 pour chaque playlist, son nom et son nombre de pistes
-- on notera l'utilisation d'une jointure externe à gauche
-- pour tenir compte des playlists vides
SELECT p.Name,
	COUNT(pt.PLaylistId)
FROM playlists p
	LEFT JOIN playlist_track pt
        ON p.PlaylistId=pt.PLaylistId
GROUP BY p.PlaylistId;

---------------------------------------------------------

--16 pour chaque piste, toutes ses info, plus le titre de l'album,
-- le genre, et le type de média

SELECT t.Name AS 'track',
    t.Composer,
    t.milliseconds,
    t.Bytes,
    t.UnitPrice,
    a.title AS 'album',
    g.Name AS 'genre',
    m.Name AS 'media type'
FROM tracks AS t
	JOIN albums AS a
        ON a.albumid = t.albumid
	JOIN genres AS g
        ON g.genreid = t.genreid
	JOIN media_types AS m
        ON m.mediatypeid = t.mediatypeid
ORDER BY t.TrackId;

---------------------------------------------------------

--17 Toutes les factures détaillées, avec leur nb de lignes de commande

SELECT i.*,
    COUNT(InvoiceLineId)
FROM invoices i
    JOIN invoice_items it
        ON i.InvoiceId=it.InvoiceId
GROUP BY i.InvoiceId;

---------------------------------------------------------

--18  le total des ventes effectuées par chaque agent commercial

SELECT e.EmployeeId,
    e.FirstName,
    e.LastName,
    SUM(i.Total)
FROM employees  e
    JOIN customers c
        ON e.EmployeeId=c.SupportRepId
    JOIN invoices i
        ON i.CustomerId=c.CustomerId
GROUP BY e.EmployeeId;

---------------------------------------------------------

--19 l'agent commercial qui a fait le plus gros chiffre d'affaire en 2009

SELECT e.EmployeeId,
    e.FirstName,
    e.LastName,
    SUM(i.Total) AS totalsales
FROM employees  e
    JOIN customers c ON e.EmployeeId=c.SupportRepId
    JOIN invoices i ON i.CustomerId=c.CustomerId
WHERE strftime('%Y',i.InvoiceDate)='2009'
-- ou bien
-- WHERE i.invoicedate between '2009-01-00' AND '2009-12-31'
GROUP BY e.EmployeeId
ORDER BY totalsales DESC
LIMIT 1;

---------------------------------------------------------

--20 idem en 2010   (intérêt ???)

SELECT e.EmployeeId,
    e.FirstName,
    e.LastName,
    SUM(i.Total) AS totalsales
FROM employees  e
    LOIN customers c
        ON e.EmployeeId=c.SupportRepId
    JOIN invoices i
        ON i.CustomerId=c.CustomerId
WHERE strftime('%Y',i.InvoiceDate)='2010'
GROUP BY e.EmployeeId
ORDER BY totalsales DESC
LIMIT 1;

---------------------------------------------------------

--21 l'agent commercial qui a fait globalement le plus gros chiffre d'affaire

SELECT e.EmployeeId,
    e.FirstName,
    e.LastName,
    sum(i.Total) AS totalsales
FROM employees  e
    JOIN customers c
        ON e.EmployeeId=c.SupportRepId
    JOIN invoices i
        ON i.CustomerId=c.CustomerId
GROUP BY e.EmployeeId
ORDER BY totalsales DESC
LIMIT 1;

---------------------------------------------------------

--22 nb de clients assignés à chaque agent

SELECT SupportRepId,
    COUNT(*)
FROM customers
GROUP BY SupportRepId;

---------------------------------------------------------

--23 le pays qui a dépensé le plus

SELECT BillingCountry,
    SUM(Total) AS somme
FROM invoices
GROUP BY BillingCountry
ORDER BY somme DESC
LIMIT 1;

---------------------------------------------------------

--24 le morceau le plus vendu en 2013

SELECT t.Name,
    sum(InvoiceLineId) AS nombre
FROM invoice_items ii
    JOIN tracks t
        ON t.TrackId=ii.TrackId
    JOIN invoices i
        ON i.InvoiceId=ii.InvoiceId
WHERE strftime('%Y',i.InvoiceDate)='2013'
GROUP BY t.trackId
ORDER BY nombre DESC
LIMIT 1;

---------------------------------------------------------

--25 les 5 morceaux les plus vendus de l'histoire

SELECT t.Name,
    SUM(InvoiceLineId) AS nombre
FROM invoice_items i
    JOIN tracks t
        ON t.TrackId=i.TrackId
GROUP BY t.trackId
ORDER BY nombre DESC
LIMIT 5;

---------------------------------------------------------

--26 Les 3 artistes les plus vendeurs

SELECT artists.name,
    SUM(i.Quantity * i.UnitPrice) AS total
FROM artists,
    albums,
    tracks,
    invoice_items i
WHERE artists.ArtistId = albums.ArtistId
    AND albums.AlbumId = tracks.AlbumId
    AND tracks.TrackId = invoice_items.TrackId
GROUP BY artists.ArtistId
ORDER BY total DESC
LIMIT 3;