🎉 First commit

main
Shad Amethyst 2 years ago
commit 60559728d3

3
.gitignore vendored

@ -0,0 +1,3 @@
secret.json
node_modules/
build/

@ -0,0 +1,12 @@
# ds52-tp (and at the same time ds53-tp)
My answers to the DS52 and DS53 practical sessions (resp. "Database Optimization" and "Business Intelligence Big Data").
I chose to avoid using Oracle SQL as much as possible, because I believe that it is a piece of software whose entire purpose is to lock people into the Oracle ecosystem.
## Running the code
You will need to run a local version of the databases; [you can find docker images for those here](https://git.shadamethyst.xyz/amethyst/ds52-db).
You can then copy `secret.json.example` to `secret.json`, and fill in the credentials accordingly.
*TODO: clean this up to automatically use docker*

@ -0,0 +1,23 @@
-- Query 1: "2 last columns with the sum() analytic function" (?)
-- From the screenshots, this query should be a copy of the query 1 of the group-by part,
-- with two new columns that add a running sum, one global and one partitionned by year.
SELECT
calendar_year_lookup.year,
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold,
SUM(SUM(shop_facts.amount_sold))
OVER (ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name)
AS total_amount_sold_global_running_sum,
SUM(SUM(shop_facts.amount_sold))
OVER (
PARTITION BY calendar_year_lookup.year
ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name
)
AS total_amount_sold_yearly_running_sum
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year
ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name;

@ -0,0 +1,20 @@
-- Query 2: "rank() by amount sold and quantity sold"
-- From the screenshots, the query should be the same as query 1 of the group-by part,
-- without grouping by year, and with two new columns that rank each shop:
-- - once by turnover (??, assuming that turnover is equal to amount_sold)
-- - once by quantity
SELECT
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold,
RANK()
OVER (ORDER BY total_amount_sold DESC)
AS amount_rank,
RANK()
OVER (ORDER BY total_quantity_sold DESC)
AS quantity_rank
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
GROUP BY outlet_lookup.shop_code
ORDER BY amount_rank;

@ -0,0 +1,26 @@
-- Query 3: "" (sic)
-- From the screenshots, the query should be the same as query 2,
-- but with years introduced
SELECT
calendar_year_lookup.year,
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold,
RANK()
OVER (
PARTITION BY calendar_year_lookup.year
ORDER BY total_amount_sold DESC
)
AS amount_rank,
RANK()
OVER (
PARTITION BY calendar_year_lookup.year
ORDER BY total_quantity_sold DESC
)
AS quantity_rank
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
GROUP BY calendar_year_lookup.year, outlet_lookup.shop_code
ORDER BY calendar_year_lookup.year, amount_rank;

@ -0,0 +1,40 @@
-- Query 4: amount sold for shop_code 351
(
SELECT
calendar_year_lookup.year,
calendar_year_lookup.month,
SUM(shop_facts.amount_sold) AS "amount sold",
SUM(SUM(shop_facts.amount_sold))
OVER(ORDER BY calendar_year_lookup.week_key)
AS "running amount sold",
SUM(SUM(shop_facts.amount_sold))
OVER(
PARTITION BY calendar_year_lookup.year
ORDER BY calendar_year_lookup.week_key
)
AS "running year amount sold"
FROM shop_facts
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
WHERE shop_facts.shop_code = 351
GROUP BY calendar_year_lookup.year, calendar_year_lookup.month
ORDER BY calendar_year_lookup.year, calendar_year_lookup.month
) UNION (
SELECT
NULL AS "year",
NULL AS "month",
SUM(shop_facts.amount_sold) AS "amount sold",
-- Because we are computing the last row by hand (grouping sets being unavailable in MySQL),
-- the last row's running amount is defined manually here. I have chosen to set it to the total sum
SUM(shop_facts.amount_sold) AS "running amount sold",
SUM(shop_facts.amount_sold) AS "running year amount sold"
FROM shop_facts
WHERE shop_facts.shop_code = 351
);
/* == TEST ==
assert(result[12]["running amount sold"] === 807190.1);
assert(result[12]["running year amount sold"] === 85616.4);
assert(result.length === 37);
assert(result[36]["amount sold"] === 3258640.5);
*/

@ -0,0 +1,2 @@
/* TODO: windowing */
SELECT * FROM shop_facts;

@ -0,0 +1,12 @@
-- Query 1: Total amount sold and total quantity for each shop name by year.
SELECT
outlet_lookup.shop_name,
calendar_year_lookup.year,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year
ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name;

@ -0,0 +1,13 @@
-- Query 2: Filtered version of query 1, to only show "e-Fashion San Francisco" and with descending years
SELECT
outlet_lookup.shop_name,
calendar_year_lookup.year,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
WHERE outlet_lookup.shop_name = "e-Fashion San Francisco"
GROUP BY calendar_year_lookup.year
ORDER BY calendar_year_lookup.year DESC;

@ -0,0 +1,12 @@
-- Query 3: Total amount sold and total quantity for each shop name in 2001.
SELECT
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
WHERE calendar_year_lookup.year = 2001
GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year
ORDER BY total_amount_sold DESC;

@ -0,0 +1,13 @@
-- Query 4: Filtered version of query 3, to only show shops with at least 1M in sales
SELECT
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
WHERE calendar_year_lookup.year = 2001
GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year
HAVING total_amount_sold >= 1000000
ORDER BY total_amount_sold DESC;

@ -0,0 +1,16 @@
-- Query 5-2: same as query 5, but with the "grouping" columns
SELECT
calendar_year_lookup.year,
outlet_lookup.shop_name,
(calendar_year_lookup.year IS NULL) as niveau_annee,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold,
(outlet_lookup.shop_name IS NULL) as niveau_magasin,
-- Note: GROUPING_ID is only available on Oracle SQL and MSSQL, so we recreate it here
(outlet_lookup.shop_name IS NULL) + (calendar_year_lookup.year IS NULL) * 2 as niveau_global
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
-- Note: shop_name must be used here instead of shop_code for NULL to be handled properly.
GROUP BY calendar_year_lookup.year ASC, outlet_lookup.shop_name ASC WITH ROLLUP;

@ -0,0 +1,12 @@
-- Query 5: same as query 1, but with the "rollup" option.
SELECT
calendar_year_lookup.year,
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
-- Note: shop_name must be used here instead of shop_code for NULL to be handled properly.
GROUP BY calendar_year_lookup.year ASC, outlet_lookup.shop_name ASC WITH ROLLUP;

@ -0,0 +1,14 @@
-- Query 6-2: same as query 6, but with a "grouping_id" column.
SELECT
calendar_year_lookup.year,
outlet_lookup.state,
outlet_lookup.shop_name,
(calendar_year_lookup.year IS NULL) * 4 + (outlet_lookup.state IS NULL) * 2 + (outlet_lookup.shop_name IS NULL) AS niveau_global,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
-- Note: "Grouping sets" is only available on Oracle SQL, so it is manually recreated here
GROUP BY calendar_year_lookup.year ASC, outlet_lookup.state, outlet_lookup.shop_name ASC WITH ROLLUP;

@ -0,0 +1,13 @@
-- Query 6: same as query 5, but with a "grouping sets" option.
SELECT
calendar_year_lookup.year,
outlet_lookup.state,
outlet_lookup.shop_name,
SUM(shop_facts.amount_sold) AS total_amount_sold,
SUM(shop_facts.quantity_sold) AS total_quantity_sold
FROM outlet_lookup
INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code
INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key
-- Note: "Grouping sets" is only available on Oracle SQL, so it is manually recreated here
GROUP BY calendar_year_lookup.year ASC, outlet_lookup.state, outlet_lookup.shop_name ASC WITH ROLLUP;

1146
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
{
"name": "ds52-tp",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"type": "module",
"author": "",
"license": "ISC",
"dependencies": {
"chalk": "^5.2.0",
"csv-string": "^4.1.1",
"deep-equal": "^2.2.0",
"mkdirp": "^2.1.5",
"mysql": "^2.18.1"
}
}

@ -0,0 +1,5 @@
{
"host": "localhost",
"user": "your_user",
"password": "your_password"
}

@ -0,0 +1,43 @@
import fs from "node:fs/promises";
import path from "node:path";
import mkdirp from "mkdirp";
const TRANSFORMS = [
(str) => str.replace(/,\n( +)/g, (_, spaces) => `\n${spaces},`),
(str) => str.replace(/(?<=\s)AS\s+([a-z].*?),?(?=\n)/gi, (_, label) => "AS `" + label + "`"),
(str) => str.replace(/(?<=\s)AS\s+["'`](.*?)["'`]/gi, (_, label) => "AS `" + label + "`"),
(str) => str.replace(
/^( *)FROM ([a-z0-9]+(?: [a-z0-9]+)?;?)$/gmi,
(_, spaces, label) => `${spaces}FROM\n${spaces} ${label}`
)
];
async function generate(folder) {
let res = "";
for (const file of sortFiles(await fs.readdir(folder))) {
const rawQuery = await fs.readFile(path.join(folder, file), "utf8");
let sql = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 0);
for (const transform of TRANSFORMS) {
sql = transform(sql);
}
res += "\n\n" + sql.trim();
}
return res.trim();
}
await mkdirp("./build");
await fs.writeFile("./build/tp1.sql", await generate("./tp1"));
function sortFiles(files) {
const collator = new Intl.Collator(undefined, {
numeric: true,
sensitivity: "base"
});
return files.sort(collator.compare);
}

@ -0,0 +1,169 @@
import mysql from "mysql";
import fs from "node:fs/promises";
import path from "node:path";
import assert from "node:assert";
import { parse } from "csv-string";
import deepEqual from "deep-equal";
import chalk from "chalk";
const secret = JSON.parse(await fs.readFile('./secret.json', 'utf8'));
await runTests({
database: 'cafe',
}, './tp1');
await runTests({
database: 'course',
}, './tp2/');
await runTests({
database: 'emode',
}, './ds53-tp1/group-by');
await runTests({
database: 'emode',
}, './ds53-tp1/analytic');
async function runTests(mysqlSettings, folder) {
const connection = mysql.createConnection({
...secret,
...mysqlSettings,
});
connection.connect();
for (const file of sortFiles(await fs.readdir(folder))) {
const rawQuery = await fs.readFile(path.join(folder, file), "utf8");
let sql = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 0).join("\n");
let comments = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 1);
let res = await query(sql.trim());
if (
process.argv.includes(file)
|| process.argv.includes(file.replace(".sql", ""))
|| path.join(folder, file).replace(".sql", "").endsWith(process.argv[process.argv.length - 1])
) {
console.table(res);
}
const result = runTest(res, comments, file);
if (result === undefined) {
console.log(chalk.yellow("NO TEST ") + file);
} else if (result) {
console.log(chalk.green("SUCCESS ") + file);
} else {
console.log(chalk.red("FAIL ") + file);
}
}
connection.end();
function query(query) {
return new Promise((resolve, reject) => {
connection.query(query, (error, results, fields) => {
if (error) return reject(error);
resolve(results);
});
});
}
}
function checkEqual(actual, expected, name) {
// Build diff of missing and superfluous items in actual
const missing = new Set();
const superfluous = new Set();
for (const row of actual) {
if (!expected.find((value) => deepEqual(value, row))) {
superfluous.add(row);
}
}
for (const row of expected) {
if (!actual.find((value) => deepEqual(value, row))) {
missing.add(row);
}
}
if (missing.size > 0 || superfluous.size > 0) {
console.error("Mismatch: there are rows missing or superfluous!");
console.error("Expected:", expected);
console.error("Actual:", actual);
console.error("Missing rows in actual:");
console.error([...missing.values()].map(row => `- ${JSON.stringify(row)}`).join("\n"));
console.error("Superfluous rows in actual");
console.error([...superfluous.values()].map(row => `- ${JSON.stringify(row)}`).join("\n"));
return false;
}
// Then, check for order
const misordered = new Set();
for (let n = 0; n < expected.length; n++) {
if (!deepEqual(actual[n], expected[n])) {
misordered.add(n);
}
}
if (misordered.size > 0) {
console.error("Mismatch: rows do not have the same order!");
console.error("Expected:", expected);
console.error("Actual:");
for (let n = 0; n < actual.length; n++) {
if (misordered.has(n)) {
console.error(`- ${chalk.red(JSON.stringify(actual[n]))}`);
} else {
console.error(` ${JSON.stringify(actual[n])}`);
}
}
return false;
}
return true;
}
function lowercaseFirstLine(str) {
const [firstLine, ...rest] = str.split("\n");
return firstLine.toLowerCase() + "\n" + rest.join("\n");
}
function sortFiles(files) {
const collator = new Intl.Collator(undefined, {
numeric: true,
sensitivity: "base"
});
return files.sort(collator.compare);
}
function runTest(queryResult, comments, file) {
let checked = false;
for (let comment of comments) {
let [, title, ...rest] = comment.split("==");
if (!rest.length || !title) continue;
title = title.trim();
rest = rest.join("==");
if (title === "RESULT") {
const csv = parse(lowercaseFirstLine(rest.trim()), { output: "objects" });
const res = queryResult.map((x) => Object.entries(x).reduce((acc, [key, value]) => {
acc[key] = String(value);
return acc;
}, {}));
if (!checkEqual(res, csv, file)) return false;
checked = true;
} else if (title === "TEST") {
const result = queryResult;
eval(rest);
checked = true;
}
}
if (!checked) {
return undefined;
} else {
return true;
}
}

@ -0,0 +1,10 @@
-- Query 1: Liste des serveurs
SELECT nomserveur, villeserveur FROM serveur;
/* == RESULT ==
"NOMSERVEUR","VILLESERVEUR"
"Durant Pierre", "BELFORT"
"Duchemin Paul", "DELLE"
"Martin Cathy", "BAVILLIERS"
"Pillot Alain", "BELFORT"
"Séré Alain", "DIJON"
*/

@ -0,0 +1,17 @@
-- Query 10: Liste des 3 consommations de type bière avec le prix le plus élevé
SELECT
cns.numcons as 'numéro',
cns.libcons as 'libellé',
cns.prixcons as 'prix'
FROM consommation cns
WHERE cns.libcons LIKE "Bière%"
ORDER BY cns.prixcons DESC, cns.libcons ASC
FETCH FIRST 3 ROWS ONLY;
/* == RESULT ==
"Numéro","Libellé","Prix"
110,"Bière 50 Cl",4.5
200,"Bière Blonde",4.5
108,"Bière 33 Cl",3
*/

@ -0,0 +1,19 @@
-- Query 11
SELECT
facture.numfacture,
facture.numtable,
tables.nomtable
FROM facture
INNER JOIN serveur ON serveur.numserveur = facture.numserveur
INNER JOIN tables ON tables.numtable = facture.numtable
WHERE
facture.datefacture = "20060222"
AND serveur.nomserveur = "Martin Cathy"
ORDER BY facture.numtable;
/* == RESULT ==
"numfacture","numtable","nomtable"
1206,3,"Fenetre1"
1204,4,"Fenetre2"
*/

@ -0,0 +1,24 @@
-- Query 12
SELECT
consommation.numcons,
consommation.libcons,
consommation.prixcons,
comprend.qte AS quantite,
comprend.qte * consommation.prixcons AS "prixcons*quantite",
serveur.nomserveur
FROM
comprend
INNER JOIN facture ON facture.numfacture = comprend.numfacture
INNER JOIN serveur ON serveur.numserveur = facture.numserveur
INNER JOIN consommation ON consommation.numcons = comprend.numcons
WHERE facture.numfacture = 1203;
/* == RESULT ==
"numcons","libcons","prixcons","quantite","prixcons*quantite","nomserveur"
101,"Café double",2,1,2,"Durant Pierre"
102,"Café crème",1.6,1,1.6,"Durant Pierre"
108,"Bière 33 Cl",3,1,3,"Durant Pierre"
121,"Fruit pressé",3,1,3,"Durant Pierre"
130,"Coca Cola",2,1,2,"Durant Pierre"
*/

@ -0,0 +1,16 @@
-- Query 13
SELECT
srv2.numserveur,
srv2.nomserveur,
srv2.villeserveur
FROM serveur srv1
INNER JOIN serveur srv2 ON srv1.villeserveur = srv2.villeserveur
WHERE
srv1.nomserveur = "Durant Pierre"
AND srv1.numserveur != srv2.numserveur;
/* == RESULT ==
"numserveur","nomserveur","villeserveur"
53,"Pillot Alain","BELFORT"
*/

@ -0,0 +1,10 @@
-- Query 14
SELECT
COUNT(tables.numtable) AS "nb tables"
FROM tables;
/* == RESULT ==
"nb tables"
6
*/

@ -0,0 +1,11 @@
-- Query 15
SELECT
COUNT(serveur.numserveur) AS "nb serveur"
FROM serveur
WHERE serveur.villeserveur = "BELFORT";
/* == RESULT ==
"nb serveur"
2
*/

@ -0,0 +1,13 @@
-- Query 16
SELECT
COUNT(facture.numfacture) AS "nb facture"
FROM
facture
INNER JOIN serveur ON serveur.numserveur = facture.numserveur
WHERE serveur.nomserveur = "Martin Cathy";
/* == RESULT ==
"nb facture"
12
*/

@ -0,0 +1,11 @@
-- Query 17
SELECT
ROUND(AVG(consommation.prixcons), 2) AS "prix moyen"
FROM
consommation;
/* == RESULT ==
"prix moyen"
2.86
*/

@ -0,0 +1,11 @@
-- Query 18
SELECT
ROUND(AVG(consommation.prixcons), 2) AS "prix moyen"
FROM consommation
WHERE REGEXP_INSTR(consommation.libcons, "^Café");
/* == RESULT ==
"prix moyen"
1.53
*/

@ -0,0 +1,18 @@
-- Query 19
SELECT
serveur.numserveur,
serveur.nomserveur,
COUNT(facture.numfacture) AS "nb factures"
FROM
facture
INNER JOIN serveur ON serveur.numserveur = facture.numserveur
GROUP BY serveur.numserveur
HAVING COUNT(facture.numfacture) >= 5
ORDER BY serveur.numserveur DESC;
/* == RESULT ==
"numserveur","nomserveur","nb factures"
53,"Pillot Alain",16
52,"Martin Cathy",12
*/

@ -0,0 +1,13 @@
-- Query 2: Liste des villes des serveurs
SELECT DISTINCT
serveur.villeserveur
FROM
serveur
ORDER BY serveur.villeserveur;
/* == RESULT ==
"VILLESERVEUR"
"BAVILLIERS"
"BELFORT"
"DELLE"
"DIJON"
*/

@ -0,0 +1,48 @@
-- Query 20
SELECT
comprend.numfacture,
SUM(comprend.qte) AS 'nb conso'
FROM
comprend
GROUP BY comprend.numfacture;
/* == RESULT ==
"numfacture","nb conso"
1000,4
1001,5
1002,2
1003,6
1004,5
1005,7
1006,2
1007,4
1008,5
1009,4
1010,4
1011,1
1012,3
1013,5
1014,2
1015,4
1016,1
1017,5
1100,2
1101,4
1102,3
1103,5
1104,7
1105,5
1106,3
1107,3
1108,2
1200,6
1201,4
1202,3
1203,5
1204,7
1205,5
1206,3
1207,5
1208,2
*/

@ -0,0 +1,8 @@
-- Query 20-2: with sort
SELECT
comprend.numfacture,
SUM(comprend.qte) AS 'nb conso'
FROM
comprend
GROUP BY comprend.numfacture
ORDER BY SUM(comprend.qte) DESC, comprend.numfacture;

@ -0,0 +1,16 @@
-- Query 21
SELECT
serveur.villeserveur as 'ville',
COUNT(serveur.numserveur) as 'nb serveurs'
FROM
serveur
GROUP BY serveur.villeserveur;
/* == RESULT ==
"Ville","Nb Serveurs"
"BAVILLIERS",1
"BELFORT",2
"DELLE",1
"DIJON",1
*/

@ -0,0 +1,27 @@
-- Query 22: nombre de factures établies chaque jour
SELECT
DATE_FORMAT(facture.datefacture, "%d/%m/%y") AS 'date',
COUNT(facture.numfacture) AS 'nb factures'
FROM facture
GROUP BY facture.datefacture
ORDER BY facture.datefacture;
/* == RESULT ==
"Date","Nb factures"
"01/12/05",1
"02/12/05",2
"04/12/05",2
"05/12/05",1
"06/12/05",1
"07/12/05",1
"08/12/05",1
"09/12/05",4
"10/12/05",1
"11/12/05",2
"12/12/05",2
"21/01/06",4
"22/01/06",5
"21/02/06",4
"22/02/06",5
*/

@ -0,0 +1,20 @@
-- Query 23
SELECT
facture.numfacture AS 'facture',
DATE_FORMAT(facture.datefacture, "%d/%m/%y") AS 'date',
COUNT(comprend.numcons) AS 'nb conso'
FROM comprend
INNER JOIN facture ON comprend.numfacture = facture.numfacture
WHERE facture.datefacture < "20060222"
GROUP BY facture.numfacture
HAVING `nb conso` > 3
ORDER BY SUM(comprend.numcons) DESC;
/* == RESULT ==
"Facture","Date","Nb conso"
1003,"04/12/05",6
1203,"21/02/06",5
1103,"21/01/06",5
1200,"21/02/06",4
*/

@ -0,0 +1,27 @@
-- Query 24
SELECT
consommation.numcons,
consommation.libcons,
(
SELECT COUNT(comprend.numfacture)
FROM comprend
WHERE comprend.numcons = consommation.numcons
) AS `nb factures`
FROM consommation
HAVING `nb factures` >= 2;
/* == RESULT ==
"NUMCONS","LIBCONS","Nb factures"
100,"Café",10
101,"Café double",13
102,"Café crème",11
105,"Chocolat",5
106,"Bière pression",6
107,"Bière 25 Cl",5
108,"Bière 33 Cl",13
110,"Bière 50 Cl",3
122,"Perrier",7
124,"Orangina",8
130,"Coca Cola",6
*/

@ -0,0 +1,19 @@
-- Query 25: same as query 13, but using a subrequest
SELECT
srv2.numserveur,
srv2.nomserveur,
srv2.villeserveur
FROM serveur srv2
WHERE
srv2.villeserveur IN (
SELECT srv1.villeserveur
FROM serveur srv1
WHERE srv1.nomserveur = "Durant Pierre"
)
AND srv2.nomserveur != "Durant Pierre";
/* == RESULT ==
"numserveur","nomserveur","villeserveur"
53,"Pillot Alain","BELFORT"
*/

@ -0,0 +1,17 @@
-- Query 26
SELECT
serveur.numserveur,
serveur.nomserveur
FROM serveur
WHERE
NOT EXISTS (
SELECT *
FROM facture
WHERE facture.numserveur = serveur.numserveur
);
/* == RESULT ==
"numserveur","nomserveur"
54,"Séré Alain"
*/

@ -0,0 +1,22 @@
-- Query 27
SELECT
serveur.numserveur,
serveur.nomserveur
FROM serveur
WHERE
NOT EXISTS (
SELECT *
FROM facture
WHERE
facture.numserveur = serveur.numserveur
AND facture.numtable = 1
);
/* == RESULT ==
"numserveur","nomserveur"
50,"Durant Pierre"
51,"Duchemin Paul"
52,"Martin Cathy"
54,"Séré Alain"
*/

@ -0,0 +1,17 @@
-- Query 28
SELECT
consommation.numcons AS 'numéro',
consommation.libcons AS 'libellé consommation'
FROM consommation
WHERE NOT EXISTS (
SELECT comprend.numcons
FROM comprend
WHERE comprend.numcons = consommation.numcons
);
/* == RESULT ==
"Numéro","Libellé Consommation"
150,"Jus de tomate"
300,"Cocktail"
*/

@ -0,0 +1,18 @@
-- Query 29
SELECT
serveur.numserveur AS 'numéro serveur',
serveur.nomserveur AS 'nom serveur',
COUNT(facture.numfacture) AS 'nb factures'
FROM serveur
LEFT OUTER JOIN facture ON facture.numserveur = serveur.numserveur
GROUP BY serveur.numserveur;
/* == RESULT ==
"Numéro Serveur","Nom Serveur","Nb factures"
50,"Durant Pierre",4
51,"Duchemin Paul",4
52,"Martin Cathy",12
53,"Pillot Alain",16
54,"Séré Alain",0
*/

@ -0,0 +1,17 @@
-- Query 3: Liste classée des serveurs par ville
SELECT
serveur.nomserveur,
serveur.villeserveur
FROM
serveur
ORDER BY
serveur.villeserveur,
serveur.nomserveur DESC;
/* == RESULT ==
"NOMSERVEUR","VILLESERVEUR"
"Martin Cathy","BAVILLIERS"
"Pillot Alain","BELFORT"
"Durant Pierre","BELFORT"
"Duchemin Paul","DELLE"
"Séré Alain","DIJON"
*/

@ -0,0 +1,17 @@
-- Query 30: Consommation la moins chère
SELECT
cns1.numcons AS 'numéro',
cns1.libcons AS 'libellé consommation',
cns1.prixcons AS 'prix le moins élevé'
FROM consommation cns1
WHERE
cns1.prixcons = (
SELECT MIN(cns2.prixcons)
FROM consommation cns2
);
/* == RESULT ==
"Numéro","Libellé Consommation","Prix le moins élevé"
100,"Café",1
*/

@ -0,0 +1,24 @@
-- Query 31: Consommations les plus chères servies par Pillot Alain
SELECT
cns1.numcons AS 'numéro',
cns1.libcons AS 'libellé consommation',
cns1.prixcons AS 'prix'
FROM
consommation cns1
WHERE
cns1.prixcons = (
SELECT MAX(cns2.prixcons)
FROM consommation cns2
INNER JOIN comprend ON comprend.numcons = cns2.numcons
INNER JOIN facture ON facture.numfacture = comprend.numfacture
INNER JOIN serveur ON facture.numserveur = serveur.numserveur
WHERE
serveur.nomserveur = "Pillot Alain"
);
/* == RESULT ==
"Numéro","Libellé Consommation","Prix"
110,"Bière 50 Cl",4.5
200,"Bière Blonde",4.5
*/

@ -0,0 +1,27 @@
-- Query 32
SELECT
tables.numtable,
SUM(comprend.qte * consommation.prixcons) AS prix
FROM tables
INNER JOIN facture ON facture.numtable = tables.numtable
INNER JOIN comprend ON comprend.numfacture = facture.numfacture
INNER JOIN consommation ON consommation.numcons = comprend.numcons
GROUP BY tables.numtable
HAVING prix = (
SELECT MAX(prix.prix)
FROM (
SELECT
SUM(comprend.qte * consommation.prixcons) AS prix
FROM tables
INNER JOIN facture ON facture.numtable = tables.numtable
INNER JOIN comprend ON comprend.numfacture = facture.numfacture
INNER JOIN consommation ON consommation.numcons = comprend.numcons
GROUP BY tables.numtable
) AS prix
);
/* == RESULT ==
"numtable","prix"
5,126.9
*/

@ -0,0 +1,28 @@
-- Query 4: Liste des consommations dont le prix unitaire > 1.5€, classée par libéllé
SELECT
cns.numcons as 'numéro',
cns.libcons as 'libellé',
cns.prixcons as 'prix'
FROM
consommation cns
WHERE
cns.prixcons > 1.5
ORDER BY cns.libcons;
/* == RESULT ==
"Numéro","Libellé","Prix"
107,"Bière 25 Cl",2.5
108,"Bière 33 Cl",3
110,"Bière 50 Cl",4.5
200,"Bière Blonde",4.5
106,"Bière pression",2.5
102,"Café crème",1.6
101,"Café double",2
105,"Chocolat",2
130,"Coca Cola",2
300,"Cocktail",8
121,"Fruit pressé",3
120,"Jus de fruit",2
150,"Jus de tomate",2
124,"Orangina",2.7
122,"Perrier",2.5
*/

@ -0,0 +1,16 @@
-- Query 5: Liste des factures du 22/02/06
SELECT
facture.numfacture,
facture.numtable,
facture.numserveur,
DATE_FORMAT(facture.datefacture, '%d/%m/%y') as 'datefact'
FROM facture
WHERE facture.datefacture = '2006-02-22';
/* == RESULT ==
"NUMFACTURE","NUMTABLE","NUMSERVEUR","DATEFACT"
1204,4,52,"22/02/06"
1205,1,53,"22/02/06"
1206,3,52,"22/02/06"
1207,5,53,"22/02/06"
1208,7,51,"22/02/06"
*/

@ -0,0 +1,11 @@
-- Query 6: Liste des serveurs dont le nom contient un i en deuxième position.
SELECT serveur.nomserveur
FROM serveur
WHERE REGEXP_INSTR(serveur.nomserveur, "^.i");
-- Alternativement:
-- WHERE serveur.nomserveur LIKE "_i%";
/* == RESULT ==
"NOMSERVEUR"
"Pillot Alain"
*/

@ -0,0 +1,13 @@
-- Query 7: Liste des serveurs dont le nom commence par un D.
SELECT
numserveur,
nomserveur
FROM serveur
WHERE serveur.nomserveur LIKE "D%"
ORDER BY serveur.nomserveur;
/* == RESULT ==
"NUMSERVEUR","NOMSERVEUR"
51,"Duchemin Paul"
50,"Durant Pierre"
*/

@ -0,0 +1,27 @@
-- Query 8: Liste des consommations classées par ordre alphabétique sur le libellé
SELECT
cns.libcons as 'libellé',
cns.numcons as 'numéro',
cns.prixcons as 'prix'
FROM consommation cns
ORDER BY cns.libcons;
/* == RESULT ==
"Libellé","Numéro","Prix"
"Bière 25 Cl",107,2.5
"Bière 33 Cl",108,3
"Bière 50 Cl",110,4.5
"Bière Blonde",200,4.5
"Bière pression",106,2.5
"Café",100,1
"Café crème",102,1.6
"Café double",101,2
"Chocolat",105,2
"Coca Cola",130,2
"Cocktail",300,8
"Fruit pressé",121,3
"Jus de fruit",120,2
"Jus de tomate",150,2
"Orangina",124,2.7
"Perrier",122,2.5
*/

@ -0,0 +1,18 @@
-- Query 9: Liste des consommations de type bière par prix décroissant et libellé croissant
SELECT
cns.numcons as 'numéro',
cns.libcons as 'libellé',
cns.prixcons as 'prix'
FROM consommation cns
WHERE cns.libcons LIKE "Bière%"
ORDER BY cns.prixcons DESC, cns.libcons ASC;
/* == RESULT ==
"Numéro","Libellé","Prix"
110,"Bière 50 Cl",4.5
200,"Bière Blonde",4.5
108,"Bière 33 Cl",3
107,"Bière 25 Cl",2.5
106,"Bière pression",2.5
*/

@ -0,0 +1 @@
SELECT * FROM coureur;
Loading…
Cancel
Save