Semaine 7

This commit is contained in:
gauvainboiche
2026-03-20 21:26:23 +01:00
parent 74d0c3f75b
commit 606e43e53f
69 changed files with 2343 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,22 @@
services:
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: company
MYSQL_USER: mysql_user
MYSQL_PASSWORD: Azerty123
command: --log_bin_trust_function_creators=1
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mysql_data:

View File

@@ -0,0 +1,208 @@
USE company;
SELECT * FROM country;
SELECT first_name "Firstname", last_name "Lastname" from employee;
select distinct department_ID from employee;
select count(job_id) from employee;
select count(distinct job_id) from employee;
-- liste des employés embauchés avant le 01.01.1991
select * from employee where hire_date < '1991-01-01';
-- FOnctions
-- -- mettre en majuscule
select upper(first_name) "Firstname" from employee;
-- -- mettre les 3 premières lettres des nom et prénom des employés
select substring(upper(first_name), 1, 3), substring(upper(last_name), 1, 3)
from employee;
-- -- prénom + nom + longueur totale du prénom+nom
select first_name, last_name,
char_length(first_name) + char_length(last_name) "Longueur totale"
from employee;
-- -- Qui gagne le plus dans l'entreprise
select first_name, last_name, salary
from employee order by salary desc limit 1;
select first_name, last_name,
salary >= (select max(salary) from employee)
from employee order by salary desc;
-- -- salaire min et max
select min(salary), max(salary), avg(salary), sum(salary) from employee;
-- -- les gens de l'IT qui gagnent moins de 5000
select first_name, last_name, department_id, salary
from employee where department_id = 60 and salary > 5000;
-- -- les gens dans la vente (80) et le mercatique (20)
select first_name, last_name, salary
from employee where department_id in (20, 80);
-- -- salaire entre 5000 et 10000
select first_name, last_name, salary
from employee where salary between 5000 and 10000;
-- -- avec une commission
select first_name, last_name, commission_pct
from employee where commission_pct != 0;
-- -- employés dont le nom de famille commance par "K"
select first_name, last_name
from employee where last_name like "K%";
-- -- employés dont le prénom contient "an"
select first_name, last_name
from employee where first_name like "%an%";
-- -- employés dont le prénom fait 4 lettres
select first_name, last_name
from employee where first_name like "____";
-- -- REGEX : nom de famille commence par "S" ou "T"
select first_name, last_name
from employee where last_name regexp "^[ST]";
-- -- le nombre de jour depuis l'embauche
select first_name, last_name, hire_date,
datediff(curdate(), hire_date) as nb_jours
from employee order by nb_jours;
-- Exercice
-- -- les commerciaux gagnant plus de 9000 triés par commission décroissante
select first_name, last_name, salary, commission_pct
from employee
where department_id = 80 and salary > 9000 order by commission_pct desc;
-- -- les postes dont le salaire est au moins le double du salaire minimum
select first_name, last_name, salary
from employee where salary > (select min(salary) from employee) * 2
order by salary asc;
-- -- les employés dont le prénom commence et fini par la même lettre
select first_name, last_name
from employee
where left(first_name, 1) = right(first_name, 1);
-- -- le top 5 des employés les mieux payés n'étant pas chefs
select first_name, last_name, salary, job_id
from employee
where employee_id not in (select manager_id from employee)
order by salary desc limit 10;
-- COURS
-- -- Jointures
-- -- -- https://cartman34.fr/informatique/sgbd/differences-entre-inner-left-right-et-outer-join-en-sql.html
select first_name, last_name, department_name
from employee e
inner join department d
on e.department_id = d.department_id;
-- -- -- LEFT avec condition : les employés qui ne sont affectés à aucun départment
select e.first_name, e.last_name, d.department_name
from employee e
left join department d
on e.department_id = d.department_id
where d.department_id is null;
-- -- -- RIGHT avec condition : la liste des départments ne contenant aucun employé
select e.first_name, e.last_name, d.department_name
from employee e
right join department d
on e.department_id = d.department_id
where e.department_id is null;
-- -- -- FULL OUTER JOIN
select e.first_name, e.last_name, d.department_name
from employee e
left join department d
on e.department_id = d.department_id
union
select e.first_name, e.last_name, d.department_name
from employee e
right join department d
on e.department_id = d.department_id;
-- -- -- NATURAL JOIN -> INNER JOIN
select location_id, street_address, city, country_name
from location
natural join country;
-- -- -- EXEMPLE : nous voulons la liste des employés travaillant à Seattle
-- -- -- On doit faire EMPLOYEE -> DEPARTMENT -> LOCATION
select e.first_name, e.last_name, l.city
from employee e
join department d
on e.department_id = d.department_id
join location l
on d.location_id = l.location_id
where lower(l.city) = "seattle";
-- -- -- EXEMPLE : nous voulons la liste des employés travaillant aux USA
-- -- -- On doit faire EMPLOYEE -> DEPARTMENT -> LOCATION -> COUNTRY
select e.first_name, e.last_name, l.city
from employee e
join department d
on e.department_id = d.department_id
join location l
on d.location_id = l.location_id
join country c
on l.country_id = c.country_id
where lower(c.country_name) like "%united%states%";
-- -- -- Prénom et nom de l'employé suivi du prénom de son chef
select e.first_name, e.last_name, m.first_name "Prénom chef", m.last_name "Nom chef"
from employee e
left join employee m
on m.employee_id = e.manager_id;
-- -- -- Nombre de gens dans chaque poste
select j.job_title, count(*)
from employee e
join job j
on e.job_id = j.job_id
group by j.job_id;
-- -- -- la liste des chefs et le nombre d'employés sous leurs ordres
-- -- -- et dont le nombre d'employés est d'au moins 5
select m.first_name "Prénom chef",
m.last_name "Nom chef",
count(e.employee_id) as count
from employee e
join employee m
on m.employee_id = e.manager_id
group by e.manager_id
having count >= 5
order by count desc;
-- -- Sous-requêtes
-- -- -- Tous les employés gagnant plus que l'employé nommé "Bull"
select first_name, last_name, salary
from employee
where salary >
(select salary from employee where lower(last_name) = "Bull");
-- -- -- Tous les employés ayant pour chef un prénommé "Payam"
-- -- -- JOINTURE
select e.first_name, e.last_name, m.first_name "Prénom chef", m.last_name "Nom chef"
from employee e
left join employee m
on m.employee_id = e.manager_id
where lower(m.first_name) = "payam";
-- -- -- Tous les employés ayant pour chef un prénommé "Payam"
-- -- -- SOUS-REQUETE
select first_name, last_name
from employee
where manager_id =
(select employee_id from employee where lower(first_name) = "payam");
-- -- -- Les employés dont le salaire est compris entre le plus petit et 3000
select first_name, last_name, salary
from employee
where salary
between (select min(salary) from employee) and 3000
order by salary asc;
-- -- -- les employés dont le chef bosse aux USA
select first_name, last_name
from employee
where manager_id in
(
select employee_id from employee where department_id in
(
select department_id from department where location_id in
(
select location_id from location where lower(country_id) = "us"
)
)
);
-- -- Création de "Vues"
-- -- Grosso modo, c'est une requête pré-enregistrée
create view `seattle_employees` as
select e.first_name, e.last_name, e.salary, d.department_name, l.city
from employee e
join department d
on e.department_id = d.department_id
join location l
on d.location_id = l.location_id
where lower(l.city) = "seattle";
select * from seattle_employees;

View File

@@ -0,0 +1,38 @@
-- Création de "Transactions"
-- -- ACID : Atomique, Cohérence, Isolation, Durabilité
-- -- minimum deux requêtes, et si l'une échoue,
-- -- la BDD revient à l'état initial. Toutes passent sinon aucune
-- -- -- On veut transférer un employé vers un autre département
-- -- -- avec un nouveau job, et archiver son poste dans job_history
START transaction;
-- -- -- 1. Archivage
insert into job_history (
employee_id,
start_date,
end_date,
job_id,
department_id
)
select
employee_id,
e.hire_date,
current_date,
e.job_id,
e.department_id
from employee e
where e.employee_id = 101;
-- -- -- 2. Mettre à jour le job et département
update employee
set
job_id = "SA_REP",
department_id = 80,
hire_date = current_date
where employee_id = 101;
COMMIT;

View File

@@ -0,0 +1,241 @@
use company;
SET FOREIGN_KEY_CHECKS = 0;
-- vide les tables et remet les compteurs a zero
truncate table job_history;
truncate table employee;
truncate table job;
truncate table department;
truncate table location;
truncate table country;
truncate table region;
-- drop et truncate
INSERT INTO region (REGION_ID, REGION_NAME) VALUES
('1', 'Europe'),
('2', 'America'),
('3', 'Asia'),
('4', 'Middle East and Africa');
INSERT INTO country (COUNTRY_ID, COUNTRY_NAME, REGION_ID) VALUES
('AR', 'Argentina', '2'),
('AU', 'Australia', '3'),
('BE', 'Belgium', '1'),
('BR', 'Brazil', '2'),
('CA', 'Canada', '2'),
('CH', 'Switzerland', '1'),
('CN', 'China', '3'),
('DE', 'Germany', '1'),
('DK', 'Denmark', '1'),
('EG', 'Egypt', '4'),
('FR', 'France', '1'),
('HK', 'HongKong', '3'),
('IL', 'Israel', '4'),
('IN', 'India', '3'),
('IT', 'Italy', '1'),
('JP', 'Japan', '3'),
('KW', 'Kuwait', '4'),
('MX', 'Mexico', '2'),
('NG', 'Nigeria', '4'),
('NL', 'Netherlands', '1'),
('SG', 'Singapore', '3'),
('UK', 'United Kingdom', '1'),
('US', 'United States of America', '2'),
('ZM', 'Zambia', '4'),
('ZW', 'Zimbabwe', '4');
INSERT INTO location (LOCATION_ID, STREET_ADDRESS, POSTAL_CODE, CITY, STATE_PROVINCE, COUNTRY_ID) VALUES
('1000', '1297 Via Cola di Rie', '989', 'Roma', '', 'IT'),
('1100', '93091 Calle della Testa', '10934', 'Venice', '', 'IT'),
('1200', '2017 Shinjuku-ku', '1689', 'Tokyo', 'Tokyo Prefecture', 'JP'),
('1300', '9450 Kamiya-cho', '6823', 'Hiroshima', '', 'JP'),
('1400', '2014 Jabberwocky Rd', '26192', 'Southlake', 'Texas', 'US'),
('1500', '2011 Interiors Blvd', '99236', 'South San Francisco', 'California', 'US'),
('1600', '2007 Zagora St', '50090', 'South Brunswick', 'New Jersey', 'US'),
('1700', '2004 Charade Rd', '98199', 'Seattle', 'Washington', 'US'),
('1800', '147 Spadina Ave', 'M5V 2L7', 'Toronto', 'Ontario', 'CA'),
('1900', '6092 Boxwood St', 'YSW 9T2', 'Whitehorse', 'Yukon', 'CA'),
('2000', '40-5-12 Laogianggen', '190518', 'Beijing', '', 'CN'),
('2100', '1298 Vileparle (E)', '490231', 'Bombay', 'Maharashtra', 'IN'),
('2200', '12-98 Victoria Street', '2901', 'Sydney', 'New South Wales', 'AU'),
('2300', '198 Clementi North', '540198', 'Singapore', '', 'SG'),
('2400', '8204 Arthur St', '', 'London', '', 'UK'),
('2500', '"Magdalen Centre', ' The Oxford ', 'OX9 9ZB', 'Oxford', 'UK'),
('2600', '9702 Chester Road', '9629850293', 'Stretford', 'Manchester', 'UK'),
('2700', 'Schwanthalerstr. 7031', '80925', 'Munich', 'Bavaria', 'DE'),
('2800', 'Rua Frei Caneca 1360', '01307-002', 'Sao Paulo', 'Sao Paulo', 'BR'),
('2900', '20 Rue des Corps-Saints', '1730', 'Geneva', 'Geneve', 'CH'),
('3000', 'Murtenstrasse 921', '3095', 'Bern', 'BE', 'CH'),
('3100', 'Pieter Breughelstraat 837', '3029SK', 'Utrecht', 'Utrecht', 'NL'),
('3200', 'Mariano Escobedo 9991', '11932', 'Mexico City', '"Distrito Federal', 'MX');
INSERT INTO department (DEPARTMENT_ID , DEPARTMENT_NAME , MANAGER_ID, LOCATION_ID) VALUES
('10', 'Administration', '200', '1700'),
('20', 'Marketing', '201', '1800'),
('30', 'Purchasing', '114', '1700'),
('40', 'Human Resources', '203', '2400'),
('50', 'Shipping', '121', '1500'),
('60', 'IT', '103', '1400'),
('70', 'Public Relations', '204', '2700'),
('80', 'Sales', '145', '2500'),
('90', 'Executive', '100', '1700'),
('100', 'Finance', '108', '1700'),
('110', 'Accounting', '205', '1700'),
('120', 'Treasury', '0', '1700'),
('130', 'Corporate Tax', '0', '1700'),
('140', 'Control And Credit', '0', '1700'),
('150', 'Shareholder Services', '0', '1700'),
('160', 'Benefits', '0', '1700'),
('170', 'Manufacturing', '0', '1700'),
('180', 'Construction', '0', '1700'),
('190', 'Contracting', '0', '1700'),
('200', 'Operations', '0', '1700'),
('210', 'IT Support', '0', '1700'),
('220', 'NOC', '0', '1700'),
('230', 'IT Helpdesk', '0', '1700'),
('240', 'Government Sales', '0', '1700'),
('250', 'Retail Sales', '0', '1700'),
('260', 'Recruiting', '0', '1700'),
('270', 'Payroll', '0', '1700');
INSERT INTO job (JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY) VALUES
('AD_PRES', 'President', '20000', '40000'),
('AD_VP', 'Administration Vice President', '15000', '30000'),
('AD_ASST', 'Administration Assistant', '3000', '6000'),
('FI_MGR', 'Finance Manager', '8200', '16000'),
('FI_ACCOUNT', 'Accountant', '4200', '9000'),
('AC_MGR', 'Accounting Manager', '8200', '16000'),
('AC_ACCOUNT', 'Public Accountant', '4200', '9000'),
('SA_MAN', 'Sales Manager', '10000', '20000'),
('SA_REP', 'Sales Representative', '6000', '12000'),
('PU_MAN', 'Purchasing Manager', '8000', '15000'),
('PU_CLERK', 'Purchasing Clerk', '2500', '5500'),
('ST_MAN', 'Stock Manager', '5500', '8500'),
('ST_CLERK', 'Stock Clerk', '2000', '5000'),
('SH_CLERK', 'Shipping Clerk', '2500', '5500'),
('IT_PROG', 'Programmer', '4000', '10000'),
('MK_MAN', 'Marketing Manager', '9000', '15000'),
('MK_REP', 'Marketing Representative', '4000', '9000'),
('HR_REP', 'Human Resources Representative', '4000', '9000'),
('PR_REP', 'Public Relations Representative', '4500', '10500');
INSERT INTO employee (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID) VALUES
('100', 'Steven', 'King', 'SKING', '515.123.4567', '1987-06-20', 'AD_PRES', '24000.00', '0.00', '0', '90'),
('101', 'Neena', 'Kochhar', 'NKOCHHAR', '515.123.4568','1987-06-20' , 'AD_VP', '17000.00', '0.00', '100', '90'),
('102', 'Lex', 'De Haan', 'LDEHAAN', '515.123.4569', '1987-06-20', 'AD_VP', '17000.00', '0.00', '100', '90'),
('103', 'Alexander', 'Hunold', 'AHUNOLD', '590.423.4567', '1987-06-20', 'IT_PROG', '9000.00', '0.00', '102', '60'),
('104', 'Bruce', 'Ernst', 'BERNST', '590.423.4568', '1987-06-21', 'IT_PROG', '6000.00', '0.00', '103', '60'),
('105', 'David', 'Austin', 'DAUSTIN', '590.423.4569', '1987-06-22', 'IT_PROG', '4800.00', '0.00', '103', '60'),
('106', 'Valli', 'Pataballa', 'VPATABAL', '590.423.4560', '1987-06-23', 'IT_PROG', '4800.00', '0.00', '103', '60'),
('107', 'Diana', 'Lorentz', 'DLORENTZ', '590.423.5567', '1987-06-24', 'IT_PROG', '4200.00', '0.00', '103', '60'),
('108', 'Nancy', 'Greenberg', 'NGREENBE', '515.124.4569', '1987-06-25', 'FI_MGR', '12000.00', '0.00', '101', '100'),
('109', 'Daniel', 'Faviet', 'DFAVIET', '515.124.4169', '1987-06-26', 'FI_ACCOUNT', '9000.00', '0.00', '108', '100'),
('110', 'John', 'Chen', 'JCHEN', '515.124.4269', '1987-06-27', 'FI_ACCOUNT', '8200.00', '0.00', '108', '100'),
('111', 'Ismael', 'Sciarra', 'ISCIARRA', '515.124.4369', '1987-06-28', 'FI_ACCOUNT', '7700.00', '0.00', '108', '100'),
('112', 'Jose Manuel', 'Urman', 'JMURMAN', '515.124.4469', '1987-06-29', 'FI_ACCOUNT', '7800.00', '0.00', '108', '100'),
('113', 'Luis', 'Popp', 'LPOPP', '515.124.4567', '1987-06-30', 'FI_ACCOUNT', '6900.00', '0.00', '108', '100'),
('114', 'Den', 'Raphaely', 'DRAPHEAL', '515.127.4561', '1987-07-01', 'PU_MAN', '11000.00', '0.00', '100', '30'),
('115', 'Alexander', 'Khoo', 'AKHOO', '515.127.4562', '1987-07-02', 'PU_CLERK', '3100.00', '0.00', '114', '30'),
('116', 'Shelli', 'Baida', 'SBAIDA', '515.127.4563', '1987-07-03', 'PU_CLERK', '2900.00', '0.00', '114', '30'),
('117', 'Sigal', 'Tobias', 'STOBIAS', '515.127.4564', '1987-07-04', 'PU_CLERK', '2800.00', '0.00', '114', '30'),
('118', 'Guy', 'Himuro', 'GHIMURO', '515.127.4565', '1987-07-05', 'PU_CLERK', '2600.00', '0.00', '114', '30'),
('119', 'Karen', 'Colmenares', 'KCOLMENA', '515.127.4566', '1987-07-06', 'PU_CLERK', '2500.00', '0.00', '114', '30'),
('120', 'Matthew', 'Weiss', 'MWEISS', '650.123.1234', '1987-07-07', 'ST_MAN', '8000.00', '0.00', '100', '50'),
('121', 'Adam', 'Fripp', 'AFRIPP', '650.123.2234', '1987-07-08', 'ST_MAN', '8200.00', '0.00', '100', '50'),
('122', 'Payam', 'Kaufling', 'PKAUFLIN', '650.123.3234', '1987-07-09', 'ST_MAN', '7900.00', '0.00', '100', '50'),
('123', 'Shanta', 'Vollman', 'SVOLLMAN', '650.123.4234', '1987-07-10', 'ST_MAN', '6500.00', '0.00', '100', '50'),
('124', 'Kevin', 'Mourgos', 'KMOURGOS', '650.123.5234', '1987-07-11', 'ST_MAN', '5800.00', '0.00', '100', '50'),
('125', 'Julia', 'Nayer', 'JNAYER', '650.124.1214', '1987-07-12', 'ST_CLERK', '3200.00', '0.00', '120', '50'),
('126', 'Irene', 'Mikkilineni', 'IMIKKILI', '650.124.1224', '1987-07-13', 'ST_CLERK', '2700.00', '0.00', '120', '50'),
('127', 'James', 'Landry', 'JLANDRY', '650.124.1334', '1987-07-14', 'ST_CLERK', '2400.00', '0.00', '120', '50'),
('128', 'Steven', 'Markle', 'SMARKLE', '650.124.1434', '1987-07-15', 'ST_CLERK', '2200.00', '0.00', '120', '50'),
('129', 'Laura', 'Bissot', 'LBISSOT', '650.124.5234', '1987-07-16', 'ST_CLERK', '3300.00', '0.00', '121', '50'),
('130', 'Mozhe', 'Atkinson', 'MATKINSO', '650.124.6234', '1987-07-17', 'ST_CLERK', '2800.00', '0.00', '121', '50'),
('131', 'James', 'Marlow', 'JAMRLOW', '650.124.7234', '1987-07-18', 'ST_CLERK', '2500.00', '0.00', '121', '50'),
('132', 'TJ', 'Olson', 'TJOLSON', '650.124.8234', '1987-07-19', 'ST_CLERK', '2100.00', '0.00', '121', '50'),
('133', 'Jason', 'Mallin', 'JMALLIN', '650.127.1934', '1987-07-20', 'ST_CLERK', '3300.00', '0.00', '122', '50'),
('134', 'Michael', 'Rogers', 'MROGERS', '650.127.1834', '1987-07-21', 'ST_CLERK', '2900.00', '0.00', '122', '50'),
('135', 'Ki', 'Gee', 'KGEE', '650.127.1734', '1987-07-22', 'ST_CLERK', '2400.00', '0.00', '122', '50'),
('136', 'Hazel', 'Philtanker', 'HPHILTAN', '650.127.1634', '1987-07-23', 'ST_CLERK', '2200.00', '0.00', '122', '50'),
('137', 'Renske', 'Ladwig', 'RLADWIG', '650.121.1234', '1987-07-24', 'ST_CLERK', '3600.00', '0.00', '123', '50'),
('138', 'Stephen', 'Stiles', 'SSTILES', '650.121.2034', '1987-07-25', 'ST_CLERK', '3200.00', '0.00', '123', '50'),
('139', 'John', 'Seo', 'JSEO', '650.121.2019', '1987-07-26', 'ST_CLERK', '2700.00', '0.00', '123', '50'),
('140', 'Joshua', 'Patel', 'JPATEL', '650.121.1834', '1987-07-27', 'ST_CLERK', '2500.00', '0.00', '123', '50'),
('141', 'Trenna', 'Rajs', 'TRAJS', '650.121.8009', '1987-07-28', 'ST_CLERK', '3500.00', '0.00', '124', '50'),
('142', 'Curtis', 'Davies', 'CDAVIES', '650.121.2994', '1987-07-29', 'ST_CLERK', '3100.00', '0.00', '124', '50'),
('143', 'Randall', 'Matos', 'RMATOS', '650.121.2874', '1987-07-30', 'ST_CLERK', '2600.00', '0.00', '124', '50'),
('144', 'Peter', 'Vargas', 'PVARGAS', '650.121.2004', '1987-07-31', 'ST_CLERK', '2500.00', '0.00', '124', '50'),
('145', 'John', 'Russell', 'JRUSSEL', '011.44.1344.429268', '1987-08-01', 'SA_MAN', '14000.00', '0.40', '100', '80'),
('146', 'Karen', 'Partners', 'KPARTNER', '011.44.1344.467268', '1987-08-02', 'SA_MAN', '13500.00', '0.30', '100', '80'),
('147', 'Alberto', 'Errazuriz', 'AERRAZUR', '011.44.1344.429278', '1987-08-03', 'SA_MAN', '12000.00', '0.30', '100', '80'),
('148', 'Gerald', 'Cambrault', 'GCAMBRAU', '011.44.1344.619268', '1987-08-04', 'SA_MAN', '11000.00', '0.30', '100', '80'),
('149', 'Eleni', 'Zlotkey', 'EZLOTKEY', '011.44.1344.429018', '1987-08-05', 'SA_MAN', '10500.00', '0.20', '100', '80'),
('150', 'Peter', 'Tucker', 'PTUCKER', '011.44.1344.129268', '1987-08-06', 'SA_REP', '10000.00', '0.30', '145', '80'),
('151', 'David', 'Bernstein', 'DBERNSTE', '011.44.1344.345268', '1987-08-07', 'SA_REP', '9500.00', '0.25', '145', '80'),
('152', 'Peter', 'Hall', 'PHALL', '011.44.1344.478968', '1987-08-08', 'SA_REP', '9000.00', '0.25', '145', '80'),
('153', 'Christopher', 'Olsen', 'COLSEN', '011.44.1344.498718', '1987-08-09', 'SA_REP', '8000.00', '0.20', '145', '80'),
('154', 'Nanette', 'Cambrault', 'NCAMBRAU', '011.44.1344.987668', '1987-08-10', 'SA_REP', '7500.00', '0.20', '145', '80'),
('155', 'Oliver', 'Tuvault', 'OTUVAULT', '011.44.1344.486508', '1987-08-11', 'SA_REP', '7000.00', '0.15', '145', '80'),
('156', 'Janette', 'King', 'JKING', '011.44.1345.429268', '1987-08-12', 'SA_REP', '10000.00', '0.35', '146', '80'),
('157', 'Patrick', 'Sully', 'PSULLY', '011.44.1345.929268', '1987-08-13', 'SA_REP', '9500.00', '0.35', '146', '80'),
('158', 'Allan', 'McEwen', 'AMCEWEN', '011.44.1345.829268', '1987-08-14', 'SA_REP', '9000.00', '0.35', '146', '80'),
('159', 'Lindsey', 'Smith', 'LSMITH', '011.44.1345.729268', '1987-08-15', 'SA_REP', '8000.00', '0.30', '146', '80'),
('160', 'Louise', 'Doran', 'LDORAN', '011.44.1345.629268', '1987-08-16', 'SA_REP', '7500.00', '0.30', '146', '80'),
('161', 'Sarath', 'Sewall', 'SSEWALL', '011.44.1345.529268', '1987-08-17', 'SA_REP', '7000.00', '0.25', '146', '80'),
('162', 'Clara', 'Vishney', 'CVISHNEY', '011.44.1346.129268', '1987-08-18', 'SA_REP', '10500.00', '0.25', '147', '80'),
('163', 'Danielle', 'Greene', 'DGREENE', '011.44.1346.229268', '1987-08-19', 'SA_REP', '9500.00', '0.15', '147', '80'),
('164', 'Mattea', 'Marvins', 'MMARVINS', '011.44.1346.329268', '1987-08-20', 'SA_REP', '7200.00', '0.10', '147', '80'),
('165', 'David', 'Lee', 'DLEE', '011.44.1346.529268', '1987-08-21', 'SA_REP', '6800.00', '0.10', '147', '80'),
('166', 'Sundar', 'Ande', 'SANDE', '011.44.1346.629268', '1987-08-22', 'SA_REP', '6400.00', '0.10', '147', '80'),
('167', 'Amit', 'Banda', 'ABANDA', '011.44.1346.729268', '1987-08-23', 'SA_REP', '6200.00', '0.10', '147', '80'),
('168', 'Lisa', 'Ozer', 'LOZER', '011.44.1343.929268', '1987-08-24', 'SA_REP', '11500.00', '0.25', '148', '80'),
('169', 'Harrison', 'Bloom', 'HBLOOM', '011.44.1343.829268', '1987-08-25', 'SA_REP', '10000.00', '0.20', '148', '80'),
('170', 'Tayler', 'Fox', 'TFOX', '011.44.1343.729268', '1987-08-26', 'SA_REP', '9600.00', '0.20', '148', '80'),
('171', 'William', 'Smith', 'WSMITH', '011.44.1343.629268', '1987-08-27', 'SA_REP', '7400.00', '0.15', '148', '80'),
('172', 'Elizabeth', 'Bates', 'EBATES', '011.44.1343.529268', '1987-08-28', 'SA_REP', '7300.00', '0.15', '148', '80'),
('173', 'Sundita', 'Kumar', 'SKUMAR', '011.44.1343.329268', '1987-08-29', 'SA_REP', '6100.00', '0.10', '148', '80'),
('174', 'Ellen', 'Abel', 'EABEL', '011.44.1644.429267', '1987-08-30', 'SA_REP', '11000.00', '0.30', '149', '80'),
('175', 'Alyssa', 'Hutton', 'AHUTTON', '011.44.1644.429266', '1987-08-31', 'SA_REP', '8800.00', '0.25', '149', '80'),
('176', 'Jonathon', 'Taylor', 'JTAYLOR', '011.44.1644.429265', '1987-09-01', 'SA_REP', '8600.00', '0.20', '149', '80'),
('177', 'Jack', 'Livingston', 'JLIVINGS', '011.44.1644.429264', '1987-09-02', 'SA_REP', '8400.00', '0.20', '149', '80'),
('178', 'Kimberely', 'Grant', 'KGRANT', '011.44.1644.429263', '1987-09-03', 'SA_REP', '7000.00', '0.15', '149', '0'),
('179', 'Charles', 'Johnson', 'CJOHNSON', '011.44.1644.429262', '1987-09-04', 'SA_REP', '6200.00', '0.10', '149', '80'),
('180', 'Winston', 'Taylor', 'WTAYLOR', '650.507.9876', '1987-09-05', 'SH_CLERK', '3200.00', '0.00', '120', '50'),
('181', 'Jean', 'Fleaur', 'JFLEAUR', '650.507.9877', '1987-09-06', 'SH_CLERK', '3100.00', '0.00', '120', '50'),
('182', 'Martha', 'Sullivan', 'MSULLIVA', '650.507.9878', '1987-09-07', 'SH_CLERK', '2500.00', '0.00', '120', '50'),
('183', 'Girard', 'Geoni', 'GGEONI', '650.507.9879', '1987-09-08', 'SH_CLERK', '2800.00', '0.00', '120', '50'),
('184', 'Nandita', 'Sarchand', 'NSARCHAN', '650.509.1876', '1987-09-09', 'SH_CLERK', '4200.00', '0.00', '121', '50'),
('185', 'Alexis', 'Bull', 'ABULL', '650.509.2876', '1987-09-10', 'SH_CLERK', '4100.00', '0.00', '121', '50'),
('186', 'Julia', 'Dellinger', 'JDELLING', '650.509.3876', '1987-09-11', 'SH_CLERK', '3400.00', '0.00', '121', '50'),
('187', 'Anthony', 'Cabrio', 'ACABRIO', '650.509.4876', '1987-09-12', 'SH_CLERK', '3000.00', '0.00', '121', '50'),
('188', 'Kelly', 'Chung', 'KCHUNG', '650.505.1876', '1987-09-13', 'SH_CLERK', '3800.00', '0.00', '122', '50'),
('189', 'Jennifer', 'Dilly', 'JDILLY', '650.505.2876', '1987-09-14', 'SH_CLERK', '3600.00', '0.00', '122', '50'),
('190', 'Timothy', 'Gates', 'TGATES', '650.505.3876', '1987-09-15', 'SH_CLERK', '2900.00', '0.00', '122', '50'),
('191', 'Randall', 'Perkins', 'RPERKINS', '650.505.4876', '1987-09-16', 'SH_CLERK', '2500.00', '0.00', '122', '50'),
('192', 'Sarah', 'Bell', 'SBELL', '650.501.1876', '1987-09-17', 'SH_CLERK', '4000.00', '0.00', '123', '50'),
('193', 'Britney', 'Everett', 'BEVERETT', '650.501.2876', '1987-09-18', 'SH_CLERK', '3900.00', '0.00', '123', '50'),
('194', 'Samuel', 'McCain', 'SMCCAIN', '650.501.3876', '1987-09-19', 'SH_CLERK', '3200.00', '0.00', '123', '50'),
('195', 'Vance', 'Jones', 'VJONES', '650.501.4876', '1987-09-20', 'SH_CLERK', '2800.00', '0.00', '123', '50'),
('196', 'Alana', 'Walsh', 'AWALSH', '650.507.9811', '1987-09-21', 'SH_CLERK', '3100.00', '0.00', '124', '50'),
('197', 'Kevin', 'Feeney', 'KFEENEY', '650.507.9822', '1987-09-22', 'SH_CLERK', '3000.00', '0.00', '124', '50'),
('198', 'Donald', 'OConnell', 'DOCONNEL', '650.507.9833', '1987-09-23', 'SH_CLERK', '2600.00', '0.00', '124', '50'),
('199', 'Douglas', 'Grant', 'DGRANT', '650.507.9844', '1987-09-24', 'SH_CLERK', '2600.00', '0.00', '124', '50'),
('200', 'Jennifer', 'Whalen', 'JWHALEN', '515.123.4444', '1987-09-25', 'AD_ASST', '4400.00', '0.00', '101', '10'),
('201', 'Michael', 'Hartstein', 'MHARTSTE', '515.123.5555', '1987-09-26', 'MK_MAN', '13000.00', '0.00', '100', '20'),
('202', 'Pat', 'Fay', 'PFAY', '603.123.6666', '1987-09-27', 'MK_REP', '6000.00', '0.00', '201', '20'),
('203', 'Susan', 'Mavris', 'SMAVRIS', '515.123.7777', '1987-09-28', 'HR_REP', '6500.00', '0.00', '101', '40'),
('204', 'Hermann', 'Baer', 'HBAER', '515.123.8888', '1987-09-29', 'PR_REP', '10000.00', '0.00', '101', '70'),
('205', 'Shelley', 'Higgins', 'SHIGGINS', '515.123.8080', '1987-09-30', 'AC_MGR', '12000.00', '0.00', '101', '110'),
('206', 'William', 'Gietz', 'WGIETZ', '515.123.8181', '1987-10-01', 'AC_ACCOUNT', '8300.00', '0.00', '205', '110');
INSERT INTO job_history (EMPLOYEE_ID, START_DATE, END_DATE, JOB_ID, DEPARTMENT_ID) VALUES
('102', '1993-01-13', '1998-07-24', 'IT_PROG', '60'),
('101', '1989-09-21', '1993-10-27', 'AC_ACCOUNT', '110'),
('201', '1996-02-17', '1999-12-19', 'MK_REP', '20'),
('114', '1998-03-24', '1999-12-31', 'ST_CLERK', '50'),
('122', '1999-01-01', '1999-12-31', 'ST_CLERK', '50'),
('200', '1987-09-17', '1993-06-17', 'AD_ASST', '90'),
('176', '1998-03-24', '1998-12-31', 'SA_REP', '80');
SET FOREIGN_KEY_CHECKS = 1;

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,4 @@
DB_HOST=localhost
DB_USER=mysql_user
DB_PASSWORD=Azerty123
DB_NAME=company

View File

@@ -0,0 +1 @@
3.12

View File

@@ -0,0 +1,115 @@
import os
from dotenv import load_dotenv
from mysql.connector import Error, connect, errorcode
load_dotenv()
db_host = os.environ.get("DB_HOST")
db_user = os.environ.get("DB_USER")
db_password = os.environ.get("DB_PASSWORD")
db_name = os.environ.get("DB_NAME")
try:
connection = connect(
host= db_host,
user= db_user,
password= db_password,
database= db_name
)
cursor = connection.cursor()
### Exemple 1 : commande
# cursor.execute("SELECT * FROM employee LIMIT 5")
# results = cursor.fetchone()
# print(results)
# ### Exemple 2 : requête complète comme variable
# query = """
# CREATE TABLE IF NOT EXISTS movies (
# id INT AUTO_INCREMENT PRIMARY KEY,
# title VARCHAR(100),
# release_year YEAR(4),
# genre VARCHAR(100),
# collection_in_mil DECIMAL(4,1)
# )
# """
# cursor.execute(query)
# # CIUD : Create, Insert, Update, Delete => Commit
# connection.commit()
### Exemple 3 : multiple requête
insert_query = """
INSERT INTO movies (title, release_year, genre, collection_in_mil)
VALUES
("Forrest Gump", 1994, "Drama", 330.2),
("INception", 2010, "Aventure", 293.7),
("Titanic", 1995, "Drama", 530.4)
"""
create_query = """
CREATE TABLE IF NOT EXISTS reviewers (
id INT AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(100),
lastname VARCHAR(100)
)
"""
insert_query_2 = """
INSERT INTO reviewers (firstname, lastname)
VALUES (%s, %s)
"""
reviewers = [
("Jean", "FAIBLE"),
("Alain", "TERIEUR"),
("Tabatha", "CLOISON"),
("Ahmed", "BIEN")
]
cursor.execute(insert_query)
cursor.execute(create_query)
cursor.executemany(insert_query_2, reviewers)
connection.commit()
cursor.execute("SELECT * FROM movies")
# lire un par un
resultat = cursor.fetchone()
print(resultat)
while resultat is not None:
print(resultat)
resultat = cursor.fetchone()
# utilisation de lot
cursor.execute("SELECT * FROM movies")
batch = cursor.fetchmany(size= 4)
while batch:
print("----")
for row in batch:
print(row)
batch = cursor.fetchmany(4)
# Out of Memory
insert_movies_query = """
INSERT INTO movies (title, release_year, genre, collection_in_mil)
VALUES (%s, %s, %s, %s)
"""
with open("movies.csv", "r") as fichier:
reader = csv.reader(fichier)
next(reader)
except Error as error:
match error.errno:
case errorcode.ER_ACCESS_DENIED_ERROR:
print("Accès refusé. Vérifier USER et PASSWORD")
case errorcode.ER_BAD_DB_ERROR:
print("BDD n'existe pas")
case _:
print(f"Erreur {error}")
finally:
if cursor is not None:
cursor.close()
if connection is not None and connection.is_connected():
connection.close()

View File

@@ -0,0 +1,10 @@
[project]
name = "connector"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"mysql-connector-python>=9.6.0",
"python-dotenv>=1.2.2",
]

View File

@@ -0,0 +1,51 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "connector"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "mysql-connector-python" },
{ name = "python-dotenv" },
]
[package.metadata]
requires-dist = [
{ name = "mysql-connector-python", specifier = ">=9.6.0" },
{ name = "python-dotenv", specifier = ">=1.2.2" },
]
[[package]]
name = "mysql-connector-python"
version = "9.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6f/6e/c89babc7de3df01467d159854414659c885152579903a8220c8db02a3835/mysql_connector_python-9.6.0.tar.gz", hash = "sha256:c453bb55347174d87504b534246fb10c589daf5d057515bf615627198a3c7ef1", size = 12254999, upload-time = "2026-02-10T12:04:52.63Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8f/d9/2a4b4d90b52f4241f0f71618cd4bd8779dd6d18db8058b0a4dd83ec0541c/mysql_connector_python-9.6.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9664e217c72dd6fb700f4c8512af90261f72d2f5d7c00c4e13e4c1e09bfa3d5e", size = 17585672, upload-time = "2026-02-10T12:03:52.955Z" },
{ url = "https://files.pythonhosted.org/packages/33/91/2495835733a054e716a17dc28404748b33f2dc1da1ae4396fb45574adf40/mysql_connector_python-9.6.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:1ed4b5c4761e5333035293e746683890e4ef2e818e515d14023fd80293bc31fa", size = 18452624, upload-time = "2026-02-10T12:03:56.153Z" },
{ url = "https://files.pythonhosted.org/packages/7a/69/e83abbbbf7f8eed855b5a5ff7285bc0afb1199418ac036c7691edf41e154/mysql_connector_python-9.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5095758dcb89a6bce2379f349da336c268c407129002b595c5dba82ce387e2a5", size = 34169154, upload-time = "2026-02-10T12:03:58.831Z" },
{ url = "https://files.pythonhosted.org/packages/82/44/67bb61c71f398fbc739d07e8dcadad94e2f655874cb32ae851454066bea0/mysql_connector_python-9.6.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ae4e7780fad950a4f267dea5851048d160f5b71314a342cdbf30b154f1c74f7", size = 34542947, upload-time = "2026-02-10T12:04:02.408Z" },
{ url = "https://files.pythonhosted.org/packages/ba/39/994c4f7e9c59d3ca534a831d18442ac4c529865db20aeaa4fd94e2af5efd/mysql_connector_python-9.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c180e0b4100d7402e03993bfac5c97d18e01d7ca9d198d742fffc245077f8ffe", size = 16515709, upload-time = "2026-02-10T12:04:04.924Z" },
{ url = "https://files.pythonhosted.org/packages/2f/58/9521aa678708ec6cebfd40524c14c3d151e4f29e3774e6086aa0a30d203b/mysql_connector_python-9.6.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e86e45a7b540ca09af8a18ecfa761e0cdeccfdb62818331614ec030ae44bfd26", size = 17585837, upload-time = "2026-02-10T12:04:07.004Z" },
{ url = "https://files.pythonhosted.org/packages/39/8d/b108f9bcce9780f6a1f91decb2af54defdaf845e237ddc42f2b4578f1cd7/mysql_connector_python-9.6.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8d3e9252384e1b7f95b07020664f2673d9c29c5e95eeda2e048b3331e190b9d4", size = 18452844, upload-time = "2026-02-10T12:04:09.418Z" },
{ url = "https://files.pythonhosted.org/packages/d6/28/735cd93d16e76dc2feb4abb3f1229a1d9475af34d80c26712fec6abe1d70/mysql_connector_python-9.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:0fa18ead33cb699ea92005695077cef09aa494eebf51164ee30c891c3eaea90c", size = 34169374, upload-time = "2026-02-10T12:04:12.13Z" },
{ url = "https://files.pythonhosted.org/packages/42/07/069983799cf4050c68f61a494f94b06f095fee6026ab0dd863a14de30867/mysql_connector_python-9.6.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a26490cb029bf7b18a1d2093101105b3526a1036b51ad01553d30138f5beb8d2", size = 34543019, upload-time = "2026-02-10T12:04:15.065Z" },
{ url = "https://files.pythonhosted.org/packages/32/00/fbeb7d666ab8153f719e620bac5abfbc74640e8ec511612493110a75fe66/mysql_connector_python-9.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:3460ed976e1b88b7284335d9397a3c519dff56d71580ca1f76ff1c0c7714c813", size = 16515701, upload-time = "2026-02-10T12:04:19.26Z" },
{ url = "https://files.pythonhosted.org/packages/70/51/13cc90b2a703784cd9a0aa0a6fce07946cf6a2abe7c8fd0b585562e250fc/mysql_connector_python-9.6.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e2cc13cd3dcdb845d636e52c4e7a9509b63da09bec6ce1b3696be53a79847e2d", size = 17585800, upload-time = "2026-02-10T12:04:21.6Z" },
{ url = "https://files.pythonhosted.org/packages/c8/6b/ce7ab998fbdd17f35a1b54624365d039045cbb2d42bbc7b03f50d7597c7b/mysql_connector_python-9.6.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:a08c2149d4b52a010c4353f18c84716d18114a4ecd00b466ea34138de2c640f2", size = 18452823, upload-time = "2026-02-10T12:04:23.995Z" },
{ url = "https://files.pythonhosted.org/packages/f9/bf/8157ed61d17878c33511dcb97c68ecaaaf6220bea5a2944ea4eba73cc63a/mysql_connector_python-9.6.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:b00228b985edd208b20f45c5e684c54e08e31e01bc1d8c3c18a36641c3be5bf7", size = 34171594, upload-time = "2026-02-10T12:04:27.401Z" },
{ url = "https://files.pythonhosted.org/packages/f7/06/5efdd28819afdb9f1487a62842fda4277febe128a3cd6e9090dbe0a6524e/mysql_connector_python-9.6.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4617ef5216da7ca32dd46afda61a1552807762434127413bba46fbe4379f59d4", size = 34542851, upload-time = "2026-02-10T12:04:31.021Z" },
{ url = "https://files.pythonhosted.org/packages/40/6a/26e08a4a79f159cd8e5b64eb10bd056e7735b65d4464d98641f59eb9ca3a/mysql_connector_python-9.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:bc782f64ca00b6b933d4c6a35568f1349d115cc4434c849b5b9edc015bee3e62", size = 17002947, upload-time = "2026-02-10T12:04:34.386Z" },
{ url = "https://files.pythonhosted.org/packages/15/dd/b3250826c29cee7816de4409a2fe5e469a68b9a89f6bfaa5eed74f05532c/mysql_connector_python-9.6.0-py2.py3-none-any.whl", hash = "sha256:44b0fb57207ebc6ae05b5b21b7968a9ed33b29187fe87b38951bad2a334d75d5", size = 480527, upload-time = "2026-02-10T12:04:36.176Z" },
]
[[package]]
name = "python-dotenv"
version = "1.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
]

View File

@@ -0,0 +1 @@
3.12

View File

@@ -0,0 +1,3 @@
```py
uv add sqlalchemy
```

View File

@@ -0,0 +1,12 @@
from sqlalchemy.orm import DeclarativeMeta, declarative_base
from database.connection import get_engine
Base: DeclarativeMeta = declarative_base() # permet à SQLAlchemy de faire la liaison Python <-> SQL
engine = get_engine()
from entities.accounts import Account
from entities.banks import Bank
from entities.clients import Client, ClientNotFound
from entities.credit_cards import CreditCard
Base.metadata.create_all(engine)

View File

View File

@@ -0,0 +1,16 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker # constructeur de classe
db_url = "sqlite:///database/bank.db"
Base = declarative_base()
# moteur_dialect
def get_engine():
return create_engine(url= db_url)
# session => cursor
def get_session():
engine = get_engine()
Session = sessionmaker(bind= engine)
return Session()

View File

@@ -0,0 +1,51 @@
from random import randint
from sqlalchemy import ForeignKey, Column, Integer, Float
from sqlalchemy.orm import relationship
from database import Base, engine
class Account(Base):
__tablename__ = "accounts"
id = Column(Integer, primary_key= True, autoincrement= True)
number = Column(Integer, nullable= False)
balance = Column(Float, default= 0, nullable= False)
client_id = Column(Integer, ForeignKey("clients.id"), nullable= False)
credit_card_id = Column(Integer, ForeignKey("credit_cards.id"))
client = relationship('Client', back_populates= "accounts")
def __init__(self, initial_deposit: int | float) -> None:
self.number = self.account_number()
self.amount = initial_deposit
def __repr__(self) -> str:
return f"\
[Numéro de compte] : {self.number}\n\
[Montant disponible] : {self.amount}"
def __eq__(self, other: 'Account'):
return self.number == other.number
def account_number(self):
number = "".join(str(randint(0,9)) for _ in range(7))
return " ".join(number[_: _ + 4] for _ in range(0,7,4))
def add_money(self, add_amount: int | float):
if add_amount < 0:
return f"{add_amount} n'est pas un entier positif. Recommencez."
self.amount += add_amount
return f"{add_amount} ont été ajoutés. Le nouveau solde est de {self.amount}."
def take_money(self, take_amount: int | float):
if take_amount < 0:
return f"{take_amount} n'est pas un entier positif. Recommencez."
self.amount -= take_amount
if self.amount < 0:
return f"{take_amount} ont été retirés. Le nouveau solde est de {self.amount}.\n\
Vous êtes débiteur et devrez payer des agios si vous ne régularisez pas votre situation."
return f"{take_amount} ont été retirés. Le nouveau solde est de {self.amount}."
Base.metadata.create_all(engine)

View File

@@ -0,0 +1,37 @@
from clients import Client, ClientNotFound
from credit_cards import CreditCard
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from database import Base, engine
class Bank(Base):
__tablename__ = "banks"
id = Column(Integer, primary_key= True, autoincrement= True)
name = Column(String(200), nullable= False)
clients = relationship("Client", back_populate= "bank", uselist= True) # type: ignore
# Le uselist définit le One ou le Many d'une relation inter-tables
# Cela permet aussi de définir la dépendance d'une table à l'autre
def __init__(self, name: str) -> None:
self.name = name
self.clients: list["Client"] = []
# Tout attribut faisant référence à une autre classe
# est une RELATION, pas une COLONNE
def __repr__(self) -> str:
return f"\
[Banque] : {self.name}"
def add_client(self, client: "Client"):
self.clients.append(client)
def request_credit_card(self, client: "Client"):
if client not in self.clients:
raise ClientNotFound()
return CreditCard(account = client.account)
Base.metadata.create_all(engine)

View File

@@ -0,0 +1,43 @@
from accounts import Account
from services import client_service
from sqlalchemy import ForeignKey, Column, Integer, String, Float
from sqlalchemy.orm import relationship
from database import Base, engine
class Client(Base):
__tablename__ = "clients"
id = Column(Integer, primary_key= True, autoincrement= True)
first_name = Column(String(200), nullable= False)
last_name = Column(String(200), nullable= False)
city = Column(String(200))
salary = Column(Float)
bank_id = Column(Integer, ForeignKey("banks.id"), nullable= False)
bank = relationship("Bank", back_populates= "clients")
account = relationship("Account", back_populates= "clients", uselist= False) # type: ignore
services = relationship("Services", back_populates= "clients", secondary= client_service)
def __init__(self, first_name: str, last_name: str, salary: float, city: str, initial_deposit: int | float = 0) -> None:
self.first_name = first_name
self.last_name = last_name
self.salary = salary
self.city = city
self.account: Account = Account(initial_deposit = initial_deposit)
def __eq__(self, other: "Client") -> bool:
return self.first_name == other.first_name and\
self.last_name == other.last_name and\
self.account == other.account # type: ignore
def __repr__(self) -> str:
return f"Client({self.first_name} {self.last_name})"
class ClientNotFound(Exception):
def __init__(self, *args: object) -> None:
super().__init__("Client not found")
Base.metadata.create_all(engine)

View File

@@ -0,0 +1,45 @@
from datetime import datetime
from random import randint
from accounts import Account
from sqlalchemy import Column, Integer, CHAR
from sqlalchemy.orm import relationship
from database import Base, engine
class CreditCard(Base):
__tablename__ = "credit_cards"
id = Column(Integer, primary_key= True, autoincrement= True)
number = Column(CHAR(19), nullable= False)
secure_code = Column(CHAR(3), nullable= False)
expire_date = Column(CHAR(5), nullable= False)
account = relationship("Account", back_populates= "credit_cards", uselist= False) # type: ignore
def __init__(self, account: "Account") -> None:
self.number = self.credit_card_number()
self.expire_date = self.expiration_date()
self.secure_code = self.security_code()
self.account = account
def __repr__(self) -> str:
return f"\
[Numéro de carte] : {self.number}\n\
[Date d'expiration] : {self.expire_date}\n\
[Code de sécurité] : {self.secure_code}"
def credit_card_number(self):
number = "".join(str(randint(0,9)) for _ in range(16))
return " ".join(number[_: _ + 4] for _ in range(0,16,4))
def security_code(self):
return "".join(str(randint(0,9)) for _ in range(3))
def expiration_date(self):
current_date = datetime.now()
future_date = current_date.replace(year=current_date.year + 5)
return str(future_date.strftime("%m/%y"))
Base.metadata.create_all(engine)

View File

@@ -0,0 +1,30 @@
from sqlalchemy import ForeignKey, Column, Integer, String, Float, Table
from sqlalchemy.orm import relationship
from database.connection import Base
# Table d'association
client_service = Table(
'client_service',
Base.metadata,
Column('client_id', Integer, ForeignKey('clients.id'), primary_key= True),
Column('service_id', Integer, ForeignKey('clients.id'), primary_key= True)
)
class Service(Base):
__tablename__ = "Services"
id = Column(Integer, primary_key= True, autoincrement= True)
name = Column(String(200), nullable= False)
description = Column(String(500))
monthly_price = Column(Float)
clients = relationship("Client", back_populates= "services", secondary= client_service)
def __init__(self, name, description= "", price= 0):
self.name = name
self.description = description
self.monthly_price = price
def __repr__(self):
return f"Service({self.name})"

View File

@@ -0,0 +1,51 @@
from entities.accounts import Account
from entities.banks import Bank
from entities.clients import Client, ClientNotFound
from entities.credit_cards import CreditCard
# from database import create_table
"""
On veut gérer des banques
Une banque a comme attributs :
- un nom
- une liste de clients
Un client a comme attributs :
- un prénom
- un nom
- un salaire
- une ville
Une banque peut ajouter un client à sa liste, ce qui va créer un compte
Un compte a :
- un numéro à 7 chiffres
- un solde initial de 0
On peut :
- déposer de l'argent
- retirer de l'argent
Une banque peut demander unne CB pour un client
Une CB a un numéro à 16 chiffres, un code de sécurité de 3 chiffres et une date d'expiration de 5 ans
"""
def create_tables():
Base.metadata.create_all(get_engine())
create_tables()
session = get_session()
# Banques
bank_001 = Bank("Crédit Agricool")
bank_002 = Bank("Société Géniale")
# Clients
client_001 = Client("Alex", "TERIEUR", 3000, "Lorient")
client_002 = Client("Emma", "TITEGOUTTE", 1750, "Brest")
session.add(bank_001)
session.add(bank_002)
session.add(client_001)
session.add(client_002)
session.commit()

View File

@@ -0,0 +1,51 @@
from entities.accounts import Account
from entities.banks import Bank
from entities.clients import Client, ClientNotFound
from entities.credit_cards import CreditCard
from database import create_table
"""
On veut gérer des banques
Une banque a comme attributs :
- un nom
- une liste de clients
Un client a comme attributs :
- un prénom
- un nom
- un salaire
- une ville
Une banque peut ajouter un client à sa liste, ce qui va créer un compte
Un compte a :
- un numéro à 7 chiffres
- un solde initial de 0
On peut :
- déposer de l'argent
- retirer de l'argent
Une banque peut demander unne CB pour un client
Une CB a un numéro à 16 chiffres, un code de sécurité de 3 chiffres et une date d'expiration de 5 ans
"""
def create_tables():
Base.metadata.create_all(get_engine())
create_tables()
session = get_session()
# Banques
bank_001 = Bank("Crédit Agricool")
bank_002 = Bank("Société Géniale")
# Clients
client_001 = Client("Alex", "TERIEUR", 3000, "Lorient")
client_002 = Client("Emma", "TITEGOUTTE", 1750, "Brest")
session.add(bank_001)
session.add(bank_002)
session.add(client_001)
session.add(client_002)
session.commit()

View File

@@ -0,0 +1,9 @@
[project]
name = "bank"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"sqlalchemy>=2.0.48",
]

108
Semaine_07/Jour_04/bank/uv.lock generated Normal file
View File

@@ -0,0 +1,108 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "bank"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "sqlalchemy" },
]
[package.metadata]
requires-dist = [{ name = "sqlalchemy", specifier = ">=2.0.48" }]
[[package]]
name = "greenlet"
version = "3.3.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" },
{ url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" },
{ url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" },
{ url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" },
{ url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" },
{ url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" },
{ url = "https://files.pythonhosted.org/packages/9b/40/cc802e067d02af8b60b6771cea7d57e21ef5e6659912814babb42b864713/greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f", size = 231081, upload-time = "2026-02-20T20:17:28.121Z" },
{ url = "https://files.pythonhosted.org/packages/58/2e/fe7f36ff1982d6b10a60d5e0740c759259a7d6d2e1dc41da6d96de32fff6/greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643", size = 230331, upload-time = "2026-02-20T20:17:23.34Z" },
{ url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" },
{ url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" },
{ url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" },
{ url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" },
{ url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" },
{ url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" },
{ url = "https://files.pythonhosted.org/packages/91/39/5ef5aa23bc545aa0d31e1b9b55822b32c8da93ba657295840b6b34124009/greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124", size = 230961, upload-time = "2026-02-20T20:16:58.461Z" },
{ url = "https://files.pythonhosted.org/packages/62/6b/a89f8456dcb06becff288f563618e9f20deed8dd29beea14f9a168aef64b/greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327", size = 230221, upload-time = "2026-02-20T20:17:37.152Z" },
{ url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" },
{ url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" },
{ url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" },
{ url = "https://files.pythonhosted.org/packages/d2/d8/09bfa816572a4d83bccd6750df1926f79158b1c36c5f73786e26dbe4ee38/greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506", size = 664160, upload-time = "2026-02-20T20:21:04.015Z" },
{ url = "https://files.pythonhosted.org/packages/48/cf/56832f0c8255d27f6c35d41b5ec91168d74ec721d85f01a12131eec6b93c/greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce", size = 1619181, upload-time = "2026-02-20T20:49:36.052Z" },
{ url = "https://files.pythonhosted.org/packages/0a/23/b90b60a4aabb4cec0796e55f25ffbfb579a907c3898cd2905c8918acaa16/greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5", size = 1687713, upload-time = "2026-02-20T20:21:11.684Z" },
{ url = "https://files.pythonhosted.org/packages/f3/ca/2101ca3d9223a1dc125140dbc063644dca76df6ff356531eb27bc267b446/greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492", size = 232034, upload-time = "2026-02-20T20:20:08.186Z" },
{ url = "https://files.pythonhosted.org/packages/f6/4a/ecf894e962a59dea60f04877eea0fd5724618da89f1867b28ee8b91e811f/greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71", size = 231437, upload-time = "2026-02-20T20:18:59.722Z" },
{ url = "https://files.pythonhosted.org/packages/98/6d/8f2ef704e614bcf58ed43cfb8d87afa1c285e98194ab2cfad351bf04f81e/greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54", size = 286617, upload-time = "2026-02-20T20:19:29.856Z" },
{ url = "https://files.pythonhosted.org/packages/5e/0d/93894161d307c6ea237a43988f27eba0947b360b99ac5239ad3fe09f0b47/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4", size = 655189, upload-time = "2026-02-20T20:47:35.742Z" },
{ url = "https://files.pythonhosted.org/packages/f5/2c/d2d506ebd8abcb57386ec4f7ba20f4030cbe56eae541bc6fd6ef399c0b41/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff", size = 658225, upload-time = "2026-02-20T20:56:02.527Z" },
{ url = "https://files.pythonhosted.org/packages/8e/30/3a09155fbf728673a1dea713572d2d31159f824a37c22da82127056c44e4/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4", size = 657907, upload-time = "2026-02-20T20:21:05.259Z" },
{ url = "https://files.pythonhosted.org/packages/f3/fd/d05a4b7acd0154ed758797f0a43b4c0962a843bedfe980115e842c5b2d08/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727", size = 1618857, upload-time = "2026-02-20T20:49:37.309Z" },
{ url = "https://files.pythonhosted.org/packages/6f/e1/50ee92a5db521de8f35075b5eff060dd43d39ebd46c2181a2042f7070385/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e", size = 1680010, upload-time = "2026-02-20T20:21:13.427Z" },
{ url = "https://files.pythonhosted.org/packages/29/4b/45d90626aef8e65336bed690106d1382f7a43665e2249017e9527df8823b/greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a", size = 237086, upload-time = "2026-02-20T20:20:45.786Z" },
]
[[package]]
name = "sqlalchemy"
version = "2.0.48"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/91/a42ae716f8925e9659df2da21ba941f158686856107a61cc97a95e7647a3/sqlalchemy-2.0.48-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:348174f228b99f33ca1f773e85510e08927620caa59ffe7803b37170df30332b", size = 2155737, upload-time = "2026-03-02T15:49:13.207Z" },
{ url = "https://files.pythonhosted.org/packages/b9/52/f75f516a1f3888f027c1cfb5d22d4376f4b46236f2e8669dcb0cddc60275/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53667b5f668991e279d21f94ccfa6e45b4e3f4500e7591ae59a8012d0f010dcb", size = 3337020, upload-time = "2026-03-02T15:50:34.547Z" },
{ url = "https://files.pythonhosted.org/packages/37/9a/0c28b6371e0cdcb14f8f1930778cb3123acfcbd2c95bb9cf6b4a2ba0cce3/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34634e196f620c7a61d18d5cf7dc841ca6daa7961aed75d532b7e58b309ac894", size = 3349983, upload-time = "2026-03-02T15:53:25.542Z" },
{ url = "https://files.pythonhosted.org/packages/1c/46/0aee8f3ff20b1dcbceb46ca2d87fcc3d48b407925a383ff668218509d132/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:546572a1793cc35857a2ffa1fe0e58571af1779bcc1ffa7c9fb0839885ed69a9", size = 3279690, upload-time = "2026-03-02T15:50:36.277Z" },
{ url = "https://files.pythonhosted.org/packages/ce/8c/a957bc91293b49181350bfd55e6dfc6e30b7f7d83dc6792d72043274a390/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:07edba08061bc277bfdc772dd2a1a43978f5a45994dd3ede26391b405c15221e", size = 3314738, upload-time = "2026-03-02T15:53:27.519Z" },
{ url = "https://files.pythonhosted.org/packages/4b/44/1d257d9f9556661e7bdc83667cc414ba210acfc110c82938cb3611eea58f/sqlalchemy-2.0.48-cp312-cp312-win32.whl", hash = "sha256:908a3fa6908716f803b86896a09a2c4dde5f5ce2bb07aacc71ffebb57986ce99", size = 2115546, upload-time = "2026-03-02T15:54:31.591Z" },
{ url = "https://files.pythonhosted.org/packages/f2/af/c3c7e1f3a2b383155a16454df62ae8c62a30dd238e42e68c24cebebbfae6/sqlalchemy-2.0.48-cp312-cp312-win_amd64.whl", hash = "sha256:68549c403f79a8e25984376480959975212a670405e3913830614432b5daa07a", size = 2142484, upload-time = "2026-03-02T15:54:34.072Z" },
{ url = "https://files.pythonhosted.org/packages/d1/c6/569dc8bf3cd375abc5907e82235923e986799f301cd79a903f784b996fca/sqlalchemy-2.0.48-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e3070c03701037aa418b55d36532ecb8f8446ed0135acb71c678dbdf12f5b6e4", size = 2152599, upload-time = "2026-03-02T15:49:14.41Z" },
{ url = "https://files.pythonhosted.org/packages/6d/ff/f4e04a4bd5a24304f38cb0d4aa2ad4c0fb34999f8b884c656535e1b2b74c/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2645b7d8a738763b664a12a1542c89c940daa55196e8d73e55b169cc5c99f65f", size = 3278825, upload-time = "2026-03-02T15:50:38.269Z" },
{ url = "https://files.pythonhosted.org/packages/fe/88/cb59509e4668d8001818d7355d9995be90c321313078c912420603a7cb95/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b19151e76620a412c2ac1c6f977ab1b9fa7ad43140178345136456d5265b32ed", size = 3295200, upload-time = "2026-03-02T15:53:29.366Z" },
{ url = "https://files.pythonhosted.org/packages/87/dc/1609a4442aefd750ea2f32629559394ec92e89ac1d621a7f462b70f736ff/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b193a7e29fd9fa56e502920dca47dffe60f97c863494946bd698c6058a55658", size = 3226876, upload-time = "2026-03-02T15:50:39.802Z" },
{ url = "https://files.pythonhosted.org/packages/37/c3/6ae2ab5ea2fa989fbac4e674de01224b7a9d744becaf59bb967d62e99bed/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:36ac4ddc3d33e852da9cb00ffb08cea62ca05c39711dc67062ca2bb1fae35fd8", size = 3265045, upload-time = "2026-03-02T15:53:31.421Z" },
{ url = "https://files.pythonhosted.org/packages/6f/82/ea4665d1bb98c50c19666e672f21b81356bd6077c4574e3d2bbb84541f53/sqlalchemy-2.0.48-cp313-cp313-win32.whl", hash = "sha256:389b984139278f97757ea9b08993e7b9d1142912e046ab7d82b3fbaeb0209131", size = 2113700, upload-time = "2026-03-02T15:54:35.825Z" },
{ url = "https://files.pythonhosted.org/packages/b7/2b/b9040bec58c58225f073f5b0c1870defe1940835549dafec680cbd58c3c3/sqlalchemy-2.0.48-cp313-cp313-win_amd64.whl", hash = "sha256:d612c976cbc2d17edfcc4c006874b764e85e990c29ce9bd411f926bbfb02b9a2", size = 2139487, upload-time = "2026-03-02T15:54:37.079Z" },
{ url = "https://files.pythonhosted.org/packages/f4/f4/7b17bd50244b78a49d22cc63c969d71dc4de54567dc152a9b46f6fae40ce/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69f5bc24904d3bc3640961cddd2523e361257ef68585d6e364166dfbe8c78fae", size = 3558851, upload-time = "2026-03-02T15:57:48.607Z" },
{ url = "https://files.pythonhosted.org/packages/20/0d/213668e9aca61d370f7d2a6449ea4ec699747fac67d4bda1bb3d129025be/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd08b90d211c086181caed76931ecfa2bdfc83eea3cfccdb0f82abc6c4b876cb", size = 3525525, upload-time = "2026-03-02T16:04:38.058Z" },
{ url = "https://files.pythonhosted.org/packages/85/d7/a84edf412979e7d59c69b89a5871f90a49228360594680e667cb2c46a828/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1ccd42229aaac2df431562117ac7e667d702e8e44afdb6cf0e50fa3f18160f0b", size = 3466611, upload-time = "2026-03-02T15:57:50.759Z" },
{ url = "https://files.pythonhosted.org/packages/86/55/42404ce5770f6be26a2b0607e7866c31b9a4176c819e9a7a5e0a055770be/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0dcbc588cd5b725162c076eb9119342f6579c7f7f55057bb7e3c6ff27e13121", size = 3475812, upload-time = "2026-03-02T16:04:40.092Z" },
{ url = "https://files.pythonhosted.org/packages/ae/ae/29b87775fadc43e627cf582fe3bda4d02e300f6b8f2747c764950d13784c/sqlalchemy-2.0.48-cp313-cp313t-win32.whl", hash = "sha256:9764014ef5e58aab76220c5664abb5d47d5bc858d9debf821e55cfdd0f128485", size = 2141335, upload-time = "2026-03-02T15:52:51.518Z" },
{ url = "https://files.pythonhosted.org/packages/91/44/f39d063c90f2443e5b46ec4819abd3d8de653893aae92df42a5c4f5843de/sqlalchemy-2.0.48-cp313-cp313t-win_amd64.whl", hash = "sha256:e2f35b4cccd9ed286ad62e0a3c3ac21e06c02abc60e20aa51a3e305a30f5fa79", size = 2173095, upload-time = "2026-03-02T15:52:52.79Z" },
{ url = "https://files.pythonhosted.org/packages/f7/b3/f437eaa1cf028bb3c927172c7272366393e73ccd104dcf5b6963f4ab5318/sqlalchemy-2.0.48-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e2d0d88686e3d35a76f3e15a34e8c12d73fc94c1dea1cd55782e695cc14086dd", size = 2154401, upload-time = "2026-03-02T15:49:17.24Z" },
{ url = "https://files.pythonhosted.org/packages/6c/1c/b3abdf0f402aa3f60f0df6ea53d92a162b458fca2321d8f1f00278506402/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49b7bddc1eebf011ea5ab722fdbe67a401caa34a350d278cc7733c0e88fecb1f", size = 3274528, upload-time = "2026-03-02T15:50:41.489Z" },
{ url = "https://files.pythonhosted.org/packages/f2/5e/327428a034407651a048f5e624361adf3f9fbac9d0fa98e981e9c6ff2f5e/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:426c5ca86415d9b8945c7073597e10de9644802e2ff502b8e1f11a7a2642856b", size = 3279523, upload-time = "2026-03-02T15:53:32.962Z" },
{ url = "https://files.pythonhosted.org/packages/2a/ca/ece73c81a918add0965b76b868b7b5359e068380b90ef1656ee995940c02/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:288937433bd44e3990e7da2402fabc44a3c6c25d3704da066b85b89a85474ae0", size = 3224312, upload-time = "2026-03-02T15:50:42.996Z" },
{ url = "https://files.pythonhosted.org/packages/88/11/fbaf1ae91fa4ee43f4fe79661cead6358644824419c26adb004941bdce7c/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8183dc57ae7d9edc1346e007e840a9f3d6aa7b7f165203a99e16f447150140d2", size = 3246304, upload-time = "2026-03-02T15:53:34.937Z" },
{ url = "https://files.pythonhosted.org/packages/fa/a8/5fb0deb13930b4f2f698c5541ae076c18981173e27dd00376dbaea7a9c82/sqlalchemy-2.0.48-cp314-cp314-win32.whl", hash = "sha256:1182437cb2d97988cfea04cf6cdc0b0bb9c74f4d56ec3d08b81e23d621a28cc6", size = 2116565, upload-time = "2026-03-02T15:54:38.321Z" },
{ url = "https://files.pythonhosted.org/packages/95/7e/e83615cb63f80047f18e61e31e8e32257d39458426c23006deeaf48f463b/sqlalchemy-2.0.48-cp314-cp314-win_amd64.whl", hash = "sha256:144921da96c08feb9e2b052c5c5c1d0d151a292c6135623c6b2c041f2a45f9e0", size = 2142205, upload-time = "2026-03-02T15:54:39.831Z" },
{ url = "https://files.pythonhosted.org/packages/83/e3/69d8711b3f2c5135e9cde5f063bc1605860f0b2c53086d40c04017eb1f77/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aee45fd2c6c0f2b9cdddf48c48535e7471e42d6fb81adfde801da0bd5b93241", size = 3563519, upload-time = "2026-03-02T15:57:52.387Z" },
{ url = "https://files.pythonhosted.org/packages/f8/4f/a7cce98facca73c149ea4578981594aaa5fd841e956834931de503359336/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cddca31edf8b0653090cbb54562ca027c421c58ddde2c0685f49ff56a1690e0", size = 3528611, upload-time = "2026-03-02T16:04:42.097Z" },
{ url = "https://files.pythonhosted.org/packages/cd/7d/5936c7a03a0b0cb0fa0cc425998821c6029756b0855a8f7ee70fba1de955/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7a936f1bb23d370b7c8cc079d5fce4c7d18da87a33c6744e51a93b0f9e97e9b3", size = 3472326, upload-time = "2026-03-02T15:57:54.423Z" },
{ url = "https://files.pythonhosted.org/packages/f4/33/cea7dfc31b52904efe3dcdc169eb4514078887dff1f5ae28a7f4c5d54b3c/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e004aa9248e8cb0a5f9b96d003ca7c1c0a5da8decd1066e7b53f59eb8ce7c62b", size = 3478453, upload-time = "2026-03-02T16:04:44.584Z" },
{ url = "https://files.pythonhosted.org/packages/c8/95/32107c4d13be077a9cae61e9ae49966a35dc4bf442a8852dd871db31f62e/sqlalchemy-2.0.48-cp314-cp314t-win32.whl", hash = "sha256:b8438ec5594980d405251451c5b7ea9aa58dda38eb7ac35fb7e4c696712ee24f", size = 2147209, upload-time = "2026-03-02T15:52:54.274Z" },
{ url = "https://files.pythonhosted.org/packages/d2/d7/1e073da7a4bc645eb83c76067284a0374e643bc4be57f14cc6414656f92c/sqlalchemy-2.0.48-cp314-cp314t-win_amd64.whl", hash = "sha256:d854b3970067297f3a7fbd7a4683587134aa9b3877ee15aa29eea478dc68f933", size = 2182198, upload-time = "2026-03-02T15:52:55.606Z" },
{ url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]

View File

@@ -0,0 +1 @@
DB_PASSWORD=MementoMarsouin96

View File

@@ -0,0 +1 @@
3.12

View File

@@ -0,0 +1,4 @@
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=MementoMarsouin96
DB_NAME=petcare

View File

@@ -0,0 +1,23 @@
from peewee import *
import os
from dotenv import load_dotenv
load_dotenv()
db_name = os.environ.get("DB_NAME")
db_user = os.environ.get("DB_USER")
db_password = os.environ.get("DB_PASSWORD")
db_host = os.environ.get("DB_HOST")
db = MySQLDatabase(
database= db_name,
user= db_user,
password= db_password,
host= db_host,
port= 3306
)
class BaseModel(Model):
class Meta:
database = db

View File

@@ -0,0 +1,10 @@
from __init__ import *
class Care(BaseModel):
id = AutoField(primary_key= True)
nom = CharField(max_length= 150, null= False)
description = TextField()
prix = DecimalField(max_digits= 6, decimal_places= 2)
class Meta:
table_name = "traitement"

View File

@@ -0,0 +1,27 @@
from __init__ import *
from classes.pet import Pet
from classes.veterinarian import Veterinarian
from classes.care import Care
class Consultation(BaseModel):
id = AutoField(primary_key= True)
date_consultation = DateField(formats= '%Y-%m-%d') # formats= '%Y-%m-%d %H:%M:%S
motif = CharField(max_length= 255, null= False)
diagnostic = TextField()
prix_consultation = DecimalField(max_digits= 6, decimal_places= 2)
animal = ForeignKeyField(Pet, backref= "animal", null= False)
veterinaire = ForeignKeyField(Veterinarian, backref= "veterinaire", null= False)
class Meta:
table_name = "consultation"
class ConsultationCare(BaseModel):
consultation = ForeignKeyField(Consultation)
traitement = ForeignKeyField(Care)
class Meta:
table_name = "consultation_traitement"
indexes= (
(("consultation", "traitement"), True),
)

View File

@@ -0,0 +1,12 @@
from __init__ import *
class Owner(BaseModel):
id = AutoField(primary_key= True)
prenom = CharField(max_length= 100, null= False)
nom = CharField(max_length= 100, null= False)
telephone = CharField(max_length= 15, null= False)
email = CharField(max_length= 150, null= False, unique= True)
ville = CharField(max_length= 100, null= False)
class Meta:
table_name = "proprietaire"

View File

@@ -0,0 +1,15 @@
from __init__ import *
from classes.owner import Owner
class Pet(BaseModel):
id = AutoField(primary_key= True)
nom = CharField(max_length= 100, null= False)
espece = CharField(max_length= 50, null= False)
race = CharField(max_length= 100, null= False)
date_naissance = DateField(formats= '%Y-%m-%d')
poids = DecimalField(max_digits= 5, decimal_places= 2)
proprietaire = ForeignKeyField(Owner, backref= "proprietaire", null= False)
class Meta:
table_name = "animal"

View File

@@ -0,0 +1,11 @@
from __init__ import *
class Veterinarian(BaseModel):
id = AutoField(primary_key= True)
prenom = CharField(max_length= 100, null= False)
nom = CharField(max_length= 100, null= False)
specialite = CharField(max_length= 100, null= False, unique= True)
telephone = CharField(max_length= 15, null= False)
class Meta:
table_name = "veterinaire"

View File

@@ -0,0 +1,127 @@
from __init__ import *
# 1. Modèles
from classes.care import *
from classes.consultation import *
from classes.owner import *
from classes.pet import *
from classes.veterinarian import *
# 2. CRUD
## 1. CREATE
try:
with db.atomic():
owner_01 = Owner.create(
prenom= "Camille",
nom= "LEMOINE",
telephone= "0656781234",
email= "camille.lemoine@mail.com",
ville= "Bordeaux"
)
pet_01 = Pet.create(
nom= "Pixel",
espece= "Chat",
race= "Bengal",
date_naissance= "2023-06-15",
poids= 4.5,
proprietaire= owner_01
)
veterinarian_01_girard = Veterinarian.get(3)
consultation_01 = Consultation.create(
date_consultation= "2025-05-15",
motif= "Première visite",
diagnostic= "RAS",
prix_consultation= 35.00,
animal= pet_01,
veterinaire= veterinarian_01_girard
)
care_01_vermifuge = Care.get(Care.nom == "Vermifuge")
care_01_puce_elec = Care.get(10)
ConsultationCare.create(consultation= consultation_01, traitement= care_01_vermifuge)
ConsultationCare.create(consultation= consultation_01, traitement= care_01_puce_elec)
except IntegrityError as error:
print(error)
## 2. READ
print("\n----- Animaux de Claire MARTIN -----")
claire_martin_pets = Pet.select().join(Owner).where(
(Owner.prenom == "Claire") &
(Owner.nom == "Martin")
)
for pet in claire_martin_pets:
print(f"{pet.nom} - {pet.espece} - {pet.poids}")
print("\n----- Consultations de REX -----")
claire_martin_rex_consultations = Consultation\
.select(Consultation, Veterinarian)\
.join(Veterinarian)\
.where(Consultation.animal == 1)
for consultation in claire_martin_rex_consultations:
print(f"{consultation.date_consultation} - {consultation.motif} - Dr {consultation.veterinaire.nom}")
print("\n----- Statistiques par espèce -----")
# Partie faite à l'aide de l'IA, notamment pour le "group_by" avant quoi je n'avais que "Chien" sans explication
# et qui m'a soufflé l'idée de l'alias qui est quand même bien pratique
stats_species = Pet.select(
Pet.espece,
fn.COUNT(Pet.id).alias("nb_pets"),
fn.AVG(Pet.poids).alias("avg_weight")
).group_by(Pet.espece)
for stat in stats_species:
print(f"{stat.nb_pets} {stat.espece}(s) au total - {round(stat.avg_weight, 2)}kg en moyenne")
## 3. UPDATE
print("\n----- Le Gros Buddy qui mange trop -----")
try:
pet_buddy = Pet.get(Pet.nom == "Buddy")
print(f"Le poids de {pet_buddy.nom} est enregistré comme étant de {pet_buddy.poids}kg.")
pet_buddy.poids = 29.50
pet_buddy.save()
print(f"Le poids de Buddy a été changé.")
print(f"Le poids de {pet_buddy.nom} est enregistré comme étant de {pet_buddy.poids}kg.")
except DoesNotExist:
print("L'animal \"Buddy\" n'existe pas.")
## 4. DELETE
print("\n----- Vous z'avez pas vu mon fils ? -----")
try:
pet_nemo = Pet.get(Pet.nom == "Nemo")
had_nemo_consultations = Consultation.select().where(Consultation.animal == pet_nemo).count()
if had_nemo_consultations > 0:
print(f"Impossible de supprimer {pet_nemo.nom}, il possède des consultations associées.")
else:
pet_nemo.delete_instance()
print(f"L'animal {pet_nemo.nom} a été supprimé de la base de données.")
except DoesNotExist:
print(f"L'animal \"Nemo\" n'a pas été trouvé dans la base de données.")
# 3. Requêtes avancées
print("\n----- Top 3 soigneurs de zanimaux -----")
top_veterinarians = Veterinarian\
.select(
Veterinarian.nom,
Veterinarian.specialite,
fn.COUNT(Consultation.id).alias("nb_cons")
)\
.join(Consultation)\
.group_by(Veterinarian.id)\
.order_by(fn.COUNT(Consultation.id)\
.desc()).limit(3)
for idx, veterinarian in enumerate(top_veterinarians):
print(f"{idx+1} - Dr {veterinarian.nom} avec {veterinarian.nb_cons} consultations.")
print("\n----- Facture n°1 détaillée -----")
print("\n----- Historique-Animal -----")
def historique_animal():

View File

@@ -0,0 +1,142 @@
CREATE DATABASE IF NOT EXISTS petcare;
USE petcare;
CREATE TABLE proprietaire (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
prenom VARCHAR(100) NOT NULL,
telephone VARCHAR(15) NOT NULL,
email VARCHAR(150) UNIQUE,
ville VARCHAR(100) NOT NULL
);
CREATE TABLE veterinaire (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
prenom VARCHAR(100) NOT NULL,
specialite VARCHAR(100) NOT NULL,
telephone VARCHAR(15) NOT NULL UNIQUE
);
CREATE TABLE animal (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
espece VARCHAR(50) NOT NULL,
race VARCHAR(100),
date_naissance DATE,
poids DECIMAL(5,2) CHECK (poids > 0),
proprietaire_id INT NOT NULL,
FOREIGN KEY (proprietaire_id) REFERENCES proprietaire(id)
);
CREATE TABLE consultation (
id INT AUTO_INCREMENT PRIMARY KEY,
date_consultation DATE NOT NULL,
motif VARCHAR(255) NOT NULL,
diagnostic TEXT,
prix_consultation DECIMAL(6,2) NOT NULL DEFAULT 35.00 CHECK (prix_consultation > 0),
animal_id INT NOT NULL,
veterinaire_id INT NOT NULL,
FOREIGN KEY (animal_id) REFERENCES animal(id),
FOREIGN KEY (veterinaire_id) REFERENCES veterinaire(id)
);
CREATE TABLE traitement (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(150) NOT NULL,
description TEXT,
prix DECIMAL(6,2) NOT NULL CHECK (prix > 0)
);
CREATE TABLE consultation_traitement (
consultation_id INT,
traitement_id INT,
dosage VARCHAR(100),
PRIMARY KEY (consultation_id, traitement_id),
FOREIGN KEY (consultation_id) REFERENCES consultation(id),
FOREIGN KEY (traitement_id) REFERENCES traitement(id)
);
-- Propriétaires
INSERT INTO proprietaire (nom, prenom, telephone, email, ville) VALUES
('Martin', 'Claire', '0612345678', 'claire.martin@mail.com', 'Paris'),
('Dupont', 'Jean', '0698765432', 'jean.dupont@mail.com', 'Lyon'),
('Bernard', 'Sophie', '0654321987', 'sophie.bernard@mail.com', 'Paris'),
('Petit', 'Thomas', '0687654321', 'thomas.petit@mail.com', 'Marseille'),
('Moreau', 'Julie', '0676543210', 'julie.moreau@mail.com', 'Lyon'),
('Garcia', 'Pierre', '0665432109', NULL, 'Toulouse'),
('Roux', 'Isabelle', '0643219876', 'isabelle.roux@mail.com', 'Paris');
-- Vétérinaires
INSERT INTO veterinaire (nom, prenom, specialite, telephone) VALUES
('Leroy', 'Marc', 'Chirurgie', '0611111111'),
('Fabre', 'Anne', 'Dermatologie', '0622222222'),
('Girard', 'Paul', 'Médecine générale', '0633333333'),
('Duval', 'Marie', 'Comportement', '0644444444');
-- Animaux
INSERT INTO animal (nom, espece, race, date_naissance, poids, proprietaire_id) VALUES
('Rex', 'Chien', 'Berger Allemand', '2020-03-15', 32.50, 1),
('Mimi', 'Chat', 'Siamois', '2019-07-22', 4.20, 1),
('Buddy', 'Chien', 'Labrador', '2021-01-10', 28.00, 2),
('Luna', 'Chat', 'Persan', '2022-05-18', 3.80, 3),
('Rocky', 'Chien', 'Bulldog', '2020-11-03', 22.50, 4),
('Nemo', 'Poisson', 'Poisson clown', '2023-01-01', 0.02, 4),
('Bella', 'Chien', 'Golden Retriever', '2019-09-14', 30.00, 5),
('Caramel', 'Chat', 'Européen', '2021-08-25', 5.10, 5),
('Max', 'Chien', 'Husky', '2022-02-28', 25.00, 6),
('Coco', 'Perroquet', 'Ara', '2018-04-12', 1.20, 7),
('Filou', 'Chat', 'Maine Coon', '2020-06-30', 7.50, 7),
('Oscar', 'Chien', 'Caniche', '2023-03-20', 8.00, 2);
-- Traitements
INSERT INTO traitement (nom, description, prix) VALUES
('Vaccination rage', 'Vaccin antirabique annuel', 45.00),
('Vaccination typhus', 'Vaccin contre le typhus félin', 40.00),
('Vermifuge', 'Traitement antiparasitaire interne', 25.00),
('Anti-puces', 'Traitement antiparasitaire externe', 30.00),
('Détartrage', 'Nettoyage dentaire sous anesthésie', 80.00),
('Radiographie', 'Examen radiologique', 60.00),
('Analyse sanguine', 'Bilan sanguin complet', 55.00),
('Antibiotiques', 'Traitement antibactérien 10 jours', 35.00),
('Castration', 'Stérilisation chirurgicale', 120.00),
('Puce électronique', 'Identification par puce', 50.00);
-- Consultations
INSERT INTO consultation (date_consultation, motif, diagnostic, prix_consultation, animal_id, veterinaire_id) VALUES
('2025-01-15', 'Visite annuelle', 'Bon état général', 35.00, 1, 1),
('2025-01-20', 'Boiterie', 'Entorse légère patte avant droite', 35.00, 3, 1),
('2025-02-10', 'Mauvaise haleine', 'Tartre important', 35.00, 2, 2),
('2025-02-14', 'Perte de poils', 'Allergie alimentaire', 45.00, 4, 2),
('2025-03-01', 'Vaccination', 'RAS', 35.00, 5, 3),
('2025-03-05', 'Griffures', 'Infection cutanée légère', 35.00, 8, 2),
('2025-03-10', 'Visite annuelle', 'Surpoids léger', 35.00, 7, 3),
('2025-03-15', 'Apathie', 'Anémie légère', 45.00, 11, 3),
('2025-04-01', 'Comportement agressif', 'Stress environnemental', 50.00, 9, 4),
('2025-04-10', 'Visite annuelle', 'Bon état général', 35.00, 10, 3),
('2025-04-15', 'Vomissements', 'Gastrite', 35.00, 12, 1),
('2025-04-20', 'Visite de contrôle', 'Guérison confirmée', 35.00, 3, 1),
('2025-05-01', 'Vaccination rappel', 'RAS', 35.00, 1, 3);
-- Consultations-Traitements
INSERT INTO consultation_traitement (consultation_id, traitement_id, dosage) VALUES
(1, 1, '1 injection'),
(1, 3, '1 comprimé'),
(2, 6, '2 clichés'),
(2, 8, '1 comprimé/jour pendant 5 jours'),
(3, 5, 'Séance complète'),
(4, 7, 'Prélèvement standard'),
(4, 4, 'Application locale'),
(5, 1, '1 injection'),
(5, 10, 'Implantation épaule gauche'),
(6, 8, '1 comprimé/jour pendant 7 jours'),
(6, 4, 'Application locale'),
(7, 3, '1 comprimé'),
(7, 7, 'Prélèvement standard'),
(8, 7, 'Prélèvement standard'),
(9, 7, 'Prélèvement standard'),
(10, 3, '1 comprimé'),
(11, 8, '1 comprimé/jour pendant 5 jours'),
(12, 6, '1 cliché'),
(13, 1, '1 injection'),
(13, 3, '1 comprimé');

View File

@@ -0,0 +1,4 @@
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=MementoMarsouin96
DB_NAME=datacenters

View File

@@ -0,0 +1,23 @@
from peewee import *
import os
from dotenv import load_dotenv
load_dotenv()
db_name = os.environ.get("DB_NAME")
db_user = os.environ.get("DB_USER")
db_password = os.environ.get("DB_PASSWORD")
db_host = os.environ.get("DB_HOST")
db = MySQLDatabase(
database= db_name,
user= db_user,
password= db_password,
host= db_host,
port= 3306
)
class BaseModel(Model):
class Meta:
database = db

View File

@@ -0,0 +1,11 @@
from __init__ import *
class Client(BaseModel):
id = AutoField(primary_key= True)
nom = CharField(max_length= 150, null= False)
email = CharField(max_length= 200, null= False)
telephone = CharField(max_length= 20, null= False)
type_contrat = CharField(max_length= 50, null= False)
class Meta:
table_name = "client"

View File

@@ -0,0 +1,12 @@
from __init__ import *
class Datacenter(BaseModel):
id = AutoField(primary_key= True)
nom = CharField(max_length= 100, null= False)
ville = CharField(max_length= 100, null= False)
pays = CharField(max_length= 100, null= False)
capacite_racks = IntegerField(null= False)
annee_ouverture = IntegerField(null= False)
class Meta:
table_name = "datacenter"

View File

@@ -0,0 +1,15 @@
from __init__ import *
from classes.client import Client
from classes.servers import Serveur
class Hebergement(BaseModel):
id = AutoField(primary_key= True)
date_debut = DateField(formats= "%Y-%m-%d", null= False)
date_fin = DateField(formats= "%Y-%m-%d", null= True)
prix_mensuel = DecimalField(max_digits= 8, decimal_places= 2, null= False)
serveur = ForeignKeyField(Serveur, backref= "serveur", null= False)
client = ForeignKeyField(Client, backref= "client", null= False)
class Meta:
table_name = "hebergement"

View File

@@ -0,0 +1,15 @@
from __init__ import *
from classes.servers import Serveur
class Intervention(BaseModel):
id = AutoField(primary_key= True)
date_intervention = DateField(formats= "%Y-%m-%d")
type_intervention = CharField(max_length= 100, null= False)
description = TextField()
duree_heures = DecimalField(max_digits= 4, decimal_places= 2, null= False)
cout = DecimalField(max_digits= 8, decimal_places= 2, null= False)
serveur = ForeignKeyField(Serveur, backref= "serveur", null= False)
class Meta:
table_name = "intervention"

View File

@@ -0,0 +1,14 @@
from __init__ import *
from classes.datacenter import Datacenter
class Salle(BaseModel):
id = AutoField(primary_key= True)
nom = CharField(max_length= 100, null= False)
etage = IntegerField(null= False)
superficie_m2 = DecimalField(max_digits= 7, decimal_places= 2, null= False)
nb_racks = IntegerField(null= False)
datacenter = ForeignKeyField(Datacenter, backref= "datacenter", null= False)
class Meta:
table_name = "salle"

View File

@@ -0,0 +1,17 @@
from __init__ import *
from classes.salle import Salle
class Serveur(BaseModel):
id = AutoField(primary_key= True)
hostname = CharField(max_length= 100, null= False)
marque = CharField(max_length= 100, null= False)
modele = CharField(max_length= 100, null= False)
cpu_cores = IntegerField(null= False)
ram_go = IntegerField(null= False)
stockage_to = DecimalField(max_digits= 5, decimal_places= 2, null= False)
date_installation = DateField(formats= "%Y-%m-%d")
salle = ForeignKeyField(Salle, backref= "salle", null= False)
class Meta:
table_name = "serveur"

View File

@@ -0,0 +1,115 @@
from __init__ import *
from classes.client import *
from classes.datacenter import *
from classes.hosting import *
from classes.intervention import *
from classes.salle import *
from classes.servers import *
# 1. Requêtes de base
print("\n----- Datacenters en France par année d'ouverture -----")
datacenters_france = (Datacenter
.select(Datacenter.nom, Datacenter.ville)
.where(Datacenter.pays == "France")
.order_by(Datacenter.annee_ouverture))
for datacenter in datacenters_france:
print(f"{datacenter.nom} - {datacenter.ville}")
print("\n----- Serveurs Dell par nom d'hôte -----")
dell_servers = (Serveur
.select(Serveur.hostname, Serveur.modele, Serveur.cpu_cores)
.where(Serveur.marque == 'Dell')
.order_by(Serveur.hostname))
for serveur in dell_servers:
print(f"{serveur.hostname} - Modèle {serveur.modele} - {serveur.cpu_cores} coeurs")
print("\n----- Interventions de mars 2025 -----")
march_2025_interventions = (Intervention
.select(Intervention.type_intervention, Intervention.cout, Intervention.date_intervention)
.where(Intervention.date_intervention.between('2025-03-01', '2025-03-31')))
for intervention in march_2025_interventions:
print(f"{intervention.date_intervention} : {intervention.type_intervention} pour {intervention.cout}€.")
# 2. Jointures
print("\n----- Liste des serveurs -----")
server_listing = (Serveur
.select(Serveur, Salle, Datacenter)
.join(Salle)
.join(Datacenter)
.order_by(Datacenter.nom, Serveur.hostname))
for server in server_listing:
print(f"{server.hostname} - Salle {server.salle.nom}, DC {server.salle.datacenter.nom}")
print("\n----- Hébergements actifs -----")
active_hostings = (Hebergement
.select(Hebergement, Client, Serveur)
.join(Client)
.switch(Hebergement)
.join(Serveur)
.where(Hebergement.date_fin.is_null())
.order_by(Hebergement.prix_mensuel.desc()))
for active_hosting in active_hostings:
print(f"{active_hosting.client.nom} - sur {active_hosting.serveur.hostname} pour {active_hosting.prix_mensuel}€ / mois.")
print("\n----- Serveurs qui n'ont jamais panné (ni poisson ni rien) -----")
servers_without_problem = (Serveur
.select(Serveur.hostname, Serveur.date_installation)
.join(Intervention, JOIN.LEFT_OUTER)
.where(Intervention.id.is_null()))
for server in servers_without_problem:
print(f"{server.hostname} - Installation {server.date_installation}.)")
print("\n----- Hébergements par client -----")
client_hostings = (Client
.select(Client.nom,
fn.COUNT(Hebergement.id).alias("nb_servers"),
fn.SUM(Hebergement.prix_mensuel).alias("monthly_price"))
.join(Hebergement)
.group_by(Client.id, Client.nom)
.order_by(fn.SUM(Hebergement.prix_mensuel).desc()))
for client_hosting in client_hostings:
total = client_hosting.monthly_price if client_hosting.monthly_price else 0
print(f"{client_hosting.nom} - {client_hosting.nb_servers} serveur(s) pour un total de {total}€ / mois.")
# 3. Agrégations
print("\n----- Liste des serveurs par marque -----")
servers_brand = (Serveur
.select(Serveur.marque, fn.COUNT(Serveur.id).alias("nb_servers"))
.group_by(Serveur.marque))
for server_brand in servers_brand:
print(f"{server_brand.marque} - {server_brand.nb_servers} serveur(s).")
print("\n----- Coût total par intervention -----")
intervention_cost = (Intervention
.select(Intervention.type_intervention,
fn.SUM(Intervention.cout).alias("cost"),
fn.AVG(Intervention.cout).alias("avg"))
.group_by(Intervention.type_intervention))
for cost in intervention_cost:
print(f"{cost.type_intervention} - {cost.cost}€ - moyenne à {round(cost.avg, 2)}€.") # Bonus pour le fun
print("\n----- Datacenters qui tournent pas trop à vide -----")
empty_datacenters = (Datacenter
.select(Datacenter.nom, fn.COUNT(Serveur.id).alias("nb_serveurs"))
.join(Salle)
.join(Serveur)
.group_by(Datacenter.id, Datacenter.nom)
.having(fn.COUNT(Serveur.id) > 3))
for datacenter in empty_datacenters:
print(f"{datacenter.nom} - {datacenter.nb_serveurs} serveurs.")
print("\n----- Mois le plus chargé de l'année -----")
heaviest_month = (Intervention
.select(fn.DATE_FORMAT(Intervention.date_intervention, '%Y-%m').alias('mois'),
fn.COUNT(Intervention.id).alias('nb_interventions'),
fn.SUM(Intervention.cout).alias('cout_total'))
.group_by(fn.DATE_FORMAT(Intervention.date_intervention, '%Y-%m'))
.order_by(fn.COUNT(Intervention.id).desc())
.limit(1))
for record in heaviest_month:
print(f"En {record.mois}, il y a eu {record.nb_interventions} interventions totalisant {record.cout_total}€.\n\
Pensez aux actionnaires !")

View File

@@ -0,0 +1,152 @@
CREATE DATABASE IF NOT EXISTS datacenters;
USE datacenters;
CREATE TABLE datacenter (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL UNIQUE,
ville VARCHAR(100) NOT NULL,
pays VARCHAR(100) NOT NULL,
capacite_racks INT NOT NULL CHECK (capacite_racks > 0),
annee_ouverture INT NOT NULL CHECK (annee_ouverture >= 2000)
);
CREATE TABLE salle (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
etage INT NOT NULL,
superficie_m2 DECIMAL(7,2) NOT NULL CHECK (superficie_m2 > 0),
nb_racks INT NOT NULL CHECK (nb_racks > 0),
datacenter_id INT NOT NULL,
FOREIGN KEY (datacenter_id) REFERENCES datacenter(id)
);
CREATE TABLE client (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(150) NOT NULL,
email VARCHAR(200) NOT NULL UNIQUE,
telephone VARCHAR(20),
type_contrat VARCHAR(50) NOT NULL CHECK (type_contrat IN ('Essentiel', 'Standard', 'Premium'))
);
CREATE TABLE serveur (
id INT AUTO_INCREMENT PRIMARY KEY,
hostname VARCHAR(100) NOT NULL UNIQUE,
marque VARCHAR(100) NOT NULL,
modele VARCHAR(100) NOT NULL,
cpu_cores INT NOT NULL CHECK (cpu_cores > 0),
ram_go INT NOT NULL CHECK (ram_go > 0),
stockage_to DECIMAL(5,2) NOT NULL CHECK (stockage_to > 0),
date_installation DATE NOT NULL,
salle_id INT NOT NULL,
FOREIGN KEY (salle_id) REFERENCES salle(id)
);
CREATE TABLE intervention (
id INT AUTO_INCREMENT PRIMARY KEY,
date_intervention DATE NOT NULL,
type_intervention VARCHAR(100) NOT NULL,
description TEXT,
duree_heures DECIMAL(4,2) NOT NULL CHECK (duree_heures > 0),
cout DECIMAL(8,2) NOT NULL CHECK (cout >= 0),
serveur_id INT NOT NULL,
FOREIGN KEY (serveur_id) REFERENCES serveur(id)
);
CREATE TABLE hebergement (
id INT AUTO_INCREMENT PRIMARY KEY,
date_debut DATE NOT NULL,
date_fin DATE,
prix_mensuel DECIMAL(8,2) NOT NULL CHECK (prix_mensuel > 0),
serveur_id INT NOT NULL,
client_id INT NOT NULL,
FOREIGN KEY (serveur_id) REFERENCES serveur(id),
FOREIGN KEY (client_id) REFERENCES client(id)
);
-- Datacenters
INSERT INTO datacenter (nom, ville, pays, capacite_racks, annee_ouverture) VALUES
('DC-Paris-Nord', 'Paris', 'France', 500, 2015),
('DC-Lyon-Est', 'Lyon', 'France', 300, 2018),
('DC-Marseille-Sud', 'Marseille', 'France', 200, 2020),
('DC-Bruxelles-Centre', 'Bruxelles', 'Belgique', 400, 2016),
('DC-Geneve-Lac', 'Genève', 'Suisse', 250, 2019);
-- Salles
INSERT INTO salle (nom, etage, superficie_m2, nb_racks, datacenter_id) VALUES
('Salle Alpha', 0, 450.00, 120, 1),
('Salle Beta', 0, 380.00, 100, 1),
('Salle Gamma', 1, 500.00, 140, 1),
('Salle Delta', 0, 300.00, 80, 2),
('Salle Epsilon', 1, 280.00, 70, 2),
('Salle Zeta', 0, 200.00, 50, 3),
('Salle Eta', 0, 350.00, 100, 4),
('Salle Theta', 1, 320.00, 90, 4),
('Salle Iota', 0, 250.00, 65, 5),
('Salle Kappa', 1, 230.00, 60, 5);
-- Clients
INSERT INTO client (nom, email, telephone, type_contrat) VALUES
('TechnoWeb SAS', 'contact@technoweb.fr', '0145678901', 'Premium'),
('StartupFlow', 'admin@startupflow.io', '0234567890', 'Standard'),
('MegaStore Europe', 'infra@megastore.eu', '0156789012', 'Premium'),
('DataLab Research', 'tech@datalab.org', '0145671234', 'Standard'),
('CloudFirst Agency', 'ops@cloudfirst.fr', '0198765432', 'Premium'),
('GreenEnergy Corp', 'it@greenenergy.com', '0187654321', 'Essentiel'),
('MediaPlus', 'support@mediaplus.fr', '0176543210', 'Standard'),
('FinanceSecure SA', 'infra@financesecure.ch', '0223456789', 'Premium'),
('EduConnect', 'admin@educonnect.fr', '0156784321', 'Essentiel'),
('LogiTrans SARL', 'it@logitrans.fr', '0167890123', 'Standard');
-- Serveurs
INSERT INTO serveur (hostname, marque, modele, cpu_cores, ram_go, stockage_to, date_installation, salle_id) VALUES
('srv-web-01', 'Dell', 'PowerEdge R750', 32, 128, 2.00, '2023-03-15', 1),
('srv-web-02', 'Dell', 'PowerEdge R750', 32, 128, 2.00, '2023-03-15', 1),
('srv-db-01', 'HP', 'ProLiant DL380', 64, 512, 8.00, '2022-06-10', 1),
('srv-app-01', 'Lenovo', 'ThinkSystem SR650', 48, 256, 4.00, '2023-09-01', 2),
('srv-storage-01', 'Dell', 'PowerEdge R760', 16, 64, 24.00, '2024-01-20', 3),
('srv-lyon-01', 'HP', 'ProLiant DL360', 32, 128, 2.00, '2023-05-12', 4),
('srv-lyon-02', 'HP', 'ProLiant DL380', 48, 256, 4.00, '2022-11-08', 4),
('srv-lyon-db-01', 'Dell', 'PowerEdge R750', 64, 512, 8.00, '2023-01-25', 5),
('srv-mars-01', 'Lenovo', 'ThinkSystem SR630', 16, 64, 1.00, '2024-03-10', 6),
('srv-mars-02', 'Lenovo', 'ThinkSystem SR650', 32, 128, 2.00, '2024-03-10', 6),
('srv-brux-01', 'Dell', 'PowerEdge R750', 48, 256, 4.00, '2021-07-15', 7),
('srv-brux-02', 'HP', 'ProLiant DL380', 64, 512, 8.00, '2021-07-15', 7),
('srv-brux-03', 'Dell', 'PowerEdge R760', 32, 128, 2.00, '2023-04-20', 8),
('srv-gen-01', 'HP', 'ProLiant DL380', 48, 256, 4.00, '2022-09-05', 9),
('srv-gen-02', 'Lenovo', 'ThinkSystem SR650', 32, 128, 2.00, '2023-08-18', 10);
-- Interventions
INSERT INTO intervention (date_intervention, type_intervention, description, duree_heures, cout, serveur_id) VALUES
('2025-01-10', 'Maintenance préventive', 'Remplacement disques préventif', 2.00, 350.00, 3),
('2025-01-15', 'Panne matérielle', 'Remplacement alimentation défectueuse', 1.50, 280.00, 1),
('2025-02-01', 'Mise à jour firmware', 'Update BIOS et firmware RAID', 1.00, 150.00, 6),
('2025-02-12', 'Panne matérielle', 'Remplacement barrette RAM défectueuse', 0.50, 420.00, 12),
('2025-02-20', 'Extension capacité', 'Ajout 256 Go RAM', 1.00, 1200.00, 7),
('2025-03-01', 'Maintenance préventive', 'Nettoyage et vérification câblage', 3.00, 200.00, 11),
('2025-03-05', 'Mise à jour firmware', 'Update BIOS', 0.50, 100.00, 4),
('2025-03-10', 'Panne matérielle', 'Remplacement ventilateur', 0.50, 180.00, 9),
('2025-03-15', 'Extension capacité', 'Ajout disque SSD 2 To', 1.00, 450.00, 14),
('2025-04-01', 'Maintenance préventive', 'Vérification générale', 2.00, 200.00, 1),
('2025-04-05', 'Panne matérielle', 'Remplacement contrôleur RAID', 2.50, 750.00, 8),
('2025-04-10', 'Mise à jour firmware', 'Update firmware stockage', 1.00, 150.00, 5),
('2025-04-15', 'Maintenance préventive', 'Remplacement pâte thermique CPU', 1.50, 120.00, 13),
('2025-05-01', 'Panne matérielle', 'Remplacement carte réseau', 1.00, 320.00, 2),
('2025-05-10', 'Extension capacité', 'Ajout 128 Go RAM', 0.50, 600.00, 10);
-- Hébergements
INSERT INTO hebergement (date_debut, date_fin, prix_mensuel, serveur_id, client_id) VALUES
('2023-04-01', NULL, 850.00, 1, 1),
('2023-04-01', NULL, 850.00, 2, 1),
('2022-07-01', NULL, 1500.00, 3, 3),
('2023-10-01', NULL, 1100.00, 4, 5),
('2024-02-01', NULL, 600.00, 5, 3),
('2023-06-01', '2025-01-31', 750.00, 6, 2),
('2023-02-01', NULL, 1100.00, 7, 4),
('2023-02-01', NULL, 1500.00, 8, 8),
('2024-04-01', NULL, 400.00, 9, 9),
('2024-04-01', NULL, 750.00, 10, 6),
('2021-08-01', NULL, 1100.00, 11, 3),
('2021-08-01', NULL, 1500.00, 12, 8),
('2023-05-01', NULL, 750.00, 13, 7),
('2022-10-01', NULL, 1100.00, 14, 5),
('2023-09-01', NULL, 750.00, 15, 10);

View File

@@ -0,0 +1,47 @@
# Evaluation 20/03/2026 - BOICHÉ Gauvain
## Démarrage
### Initialisation
```bash
uv init --python 3.12
uv run main.py
.venv/Scripts/activate
uv add dotenv
uv add peewee pymysql
```
### Fichier .env
Les "secrets" sont gérés pour l'occasion dans un fichier .env
Normalement, on met aussi un fichier
`.gitignore`
Dont le contenu mentionne :
`*.env`
Pour l'exercice évidemment, je garde le fichier en clair.
## Partie 1
## Partie 2
### Requêtes normales
Avoir une requête SQL normale fonctionne :
```sql
select nom, ville
from datacenters.datacenter
where pays = "France"
order by annee_ouverture;
```
Maintenant faut les traduire.

View File

@@ -0,0 +1,19 @@
services:
mysql:
image: mysql:8.0
container_name: mysql_evaluation
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
command: --log_bin_trust_function_creators=1
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mysql_data:

View File

@@ -0,0 +1,11 @@
[project]
name = "boiche-gauvain-eval-20-03-2026"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"dotenv>=0.9.9",
"peewee>=4.0.2",
"pymysql>=1.1.2",
]

View File

@@ -0,0 +1,58 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "boiche-gauvain-eval-20-03-2026"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "dotenv" },
{ name = "peewee" },
{ name = "pymysql" },
]
[package.metadata]
requires-dist = [
{ name = "dotenv", specifier = ">=0.9.9" },
{ name = "peewee", specifier = ">=4.0.2" },
{ name = "pymysql", specifier = ">=1.1.2" },
]
[[package]]
name = "dotenv"
version = "0.9.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dotenv" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892, upload-time = "2025-02-19T22:15:01.647Z" },
]
[[package]]
name = "peewee"
version = "4.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/9b/3439dcc3ed5138eb26f28fc208f958ca97b831f5f898b26d5354302e5df4/peewee-4.0.2.tar.gz", hash = "sha256:fd5d026ce7787c6cd3a84316e665a76b72c9c4e87322598c413f44604fa6c38d", size = 714081, upload-time = "2026-03-15T15:46:30.049Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/8e/943f57ce32eb005c7037110a759e2ebfb22e467a9a0efcb6d516c5bf00c6/peewee-4.0.2-py3-none-any.whl", hash = "sha256:86d5d16bcda5bbe017a108f6efc57abaac8d89277915541904542df9d2a7f25d", size = 143344, upload-time = "2026-03-15T15:46:28.778Z" },
]
[[package]]
name = "pymysql"
version = "1.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f5/ae/1fe3fcd9f959efa0ebe200b8de88b5a5ce3e767e38c7ac32fb179f16a388/pymysql-1.1.2.tar.gz", hash = "sha256:4961d3e165614ae65014e361811a724e2044ad3ea3739de9903ae7c21f539f03", size = 48258, upload-time = "2025-08-24T12:55:55.146Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/4c/ad33b92b9864cbde84f259d5df035a6447f91891f5be77788e2a3892bce3/pymysql-1.1.2-py3-none-any.whl", hash = "sha256:e6b1d89711dd51f8f74b1631fe08f039e7d76cf67a42a323d3178f0f25762ed9", size = 45300, upload-time = "2025-08-24T12:55:53.394Z" },
]
[[package]]
name = "python-dotenv"
version = "1.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
]

View File

@@ -0,0 +1,5 @@
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=MementoMarsouin96
DB_NAME=company
DB_PORT=3306

View File

@@ -0,0 +1 @@
3.12

View File

@@ -0,0 +1,11 @@
Normalement, on met aussi un fichier
`.gitignore`
Dont le contenu mentionne :
```
*.env
```
Pour l'exercice évidemment, je garde le fichier en clair.

View File

@@ -0,0 +1,19 @@
services:
mysql:
image: mysql:8.0
container_name: mysql_peewee
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
command: --log_bin_trust_function_creators=1
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mysql_data:

View File

@@ -0,0 +1,123 @@
from peewee import *
# import os
# from dotenv import load_dotenv
# load_dotenv()
# db_name = os.environ.get("DB_NAME")
# db_user = os.environ.get("DB_USER")
# db_password = os.environ.get("DB_PASSWORD")
# db_host = os.environ.get("DB_HOST")
# db_port = os.environ.get("DB_PORT")
db_name = "company"
db_user = "root"
db_password = "MementoMarsouin96"
db_host = "localhost"
db_port = 3306
db = MySQLDatabase(
database= db_name,
user= db_user,
password= db_password,
host= db_host,
port= db_port
)
# équivalent de "Base = declarative_base()"
class BaseModel(Model):
class Meta:
database = db
class Department(BaseModel):
department_id = AutoField(primary_key= True)
department_name = CharField(max_length= 50, null= False, unique= True)
location_id = DecimalField(max_digits= 4, decimal_places= 0, null= False)
# équivalent de "__tablename__ = "truc""
class Meta:
table_name = "departments"
class Employee(BaseModel):
employee_id = AutoField(primary_key= True)
first_name = CharField(max_length= 50, null= False)
last_name = CharField(max_length= 50, null= False)
email = CharField(max_length= 50, null= False, unique= True)
salary = IntegerField(null= False)
department = ForeignKeyField(Department, backref= "employees", null= False)
class Meta:
table_name = "employees"
db.connect()
db.create_tables([Department, Employee])
try:
it_dept = Department.create(department_name= "IT", location_id= 1400)
except IntegrityError:
print("Département déjà existant.")
it_dept = Department.get(Department.department_name == "IT")
try:
Employee.create(
first_name= "Alice",
last_name= "Smith",
email= "a.smith@company.au",
salary= 4000,
department= it_dept # utiliser l'OBJET, pas le nom de l'objet
)
except IntegrityError:
print("Employé(e) déjà existant(e).")
new_employees = [
{'first_name': 'Marie', 'last_name': 'Dupont', 'email': 'mdupont', 'salary': 4500},
{'first_name': 'Jean', 'last_name': 'Martin', 'email': 'jmartin', 'salary': 5200},
{'first_name': 'Sophie', 'last_name': 'Bernard', 'email': 'sbernard', 'salary': 4800},
]
# with db.atomic():
# Employee.insert_many(new_employees).execute()
employee_01 = Employee.get(1)
print(employee_01.first_name, employee_01.last_name)
employee_02 = Employee.get(Employee.email == "a.smith@company.au")
print(employee_02.first_name, employee_02.salary)
try:
employee_76 = Employee.get(76)
except DoesNotExist:
print("L'employé(e) 76 n'existe pas.")
employee_select_01 = Employee.select() # SELECT * FROM employees
print(employee_select_01)
for employee in employee_select_01:
print(employee.first_name, employee.last_name, employee.email)
employee_select_02 = Employee.select().where(
(Employee.salary > 8000) & (Employee.department == it_dept)
)
print(employee_select_02)
# pagination
page_01 = Employee.select().order_by(Employee.employee_id).paginate(1, 10)
# compter une valeur
salary_01 = Employee.select().where(Employee.salary > 10000).count()
# Jointures (LEFT JOIN, RIGHT JOIN etc)
### FULL JOIN
query = (Employee
.select(Employee, Department)
.join(Department)
.where(Department.department_name == "IT"))
### Employés affectés à un département
### et ceux non affectés à un département
query = (Employee
.select(Employee, Department)
.join(Department, JOIN.LEFT_OUTER)
.where(Department.department_name == "IT"))

View File

@@ -0,0 +1,10 @@
[project]
name = "orm-peewee"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"peewee>=4.0.2",
"pymysql>=1.1.2",
]

View File

@@ -0,0 +1,105 @@
from peewee import *
# import os
# from dotenv import load_dotenv
# load_dotenv()
# db_name = os.environ.get("DB_NAME")
# db_user = os.environ.get("DB_USER")
# db_password = os.environ.get("DB_PASSWORD")
# db_host = os.environ.get("DB_HOST")
# db_port = os.environ.get("DB_PORT")
db_name = "company"
db_user = "root"
db_password = "MementoMarsouin96"
db_host = "localhost"
db_port = 3306
db = MySQLDatabase(
database= db_name,
user= db_user,
password= db_password,
host= db_host,
port= db_port
)
# équivalent de "Base = declarative_base()"
class BaseModel(Model):
class Meta:
database = db
# Relations One-To-Many
class User(BaseModel):
username = CharField(unique= True)
email = CharField()
class Meta:
table_name = "user"
class Todo(BaseModel):
title = CharField()
is_done = BooleanField(default= False)
user= ForeignKeyField(User, backref= "todos") # l'accès inverse est géré automatiquement
class Meta:
table_name = "todos"
class Tag(BaseModel):
name = CharField(unique= True)
class Meta:
table_name = "tag"
class TodoTag(BaseModel):
todo = ForeignKeyField(Todo)
tag = ForeignKeyField(Tag)
class Meta:
table_name = 'todo_tag'
indexes= (
(('todo', 'tag'), True),
)
class Profile(BaseModel):
user = ForeignKeyField(User, unique= True, backref= "profile") # One-To-One
bio = TextField(null= True)
avatar = CharField(null= True)
class Meta:
table_name = "profile"
db.connect()
db.create_tables([User, Todo, Profile, Tag, TodoTag])
try:
alice = User.create(username= "Alice", email= "a.smith@company.au")
Todo.create(title= "Apprendre Python", user= alice)
Todo.create(title= "Apprendre JS", user= alice)
Todo.create(title= "Apprendre COBOL", user= alice)
for todo in alice.todos:
print(todo.title, todo.is_done)
except IntegrityError as error:
print(error)
try:
Profile.create(
user= User.get(1),
bio = 'Developpeur',
avatar= 'http://example.com'
)
except IntegrityError as error:
print(error)
try:
tag_urgent = Tag.create(name= "Urgent")
tag_perso = Tag.create(name= "Perso")
tag_pro = Tag.create(name= "Pro")
todo_cobol = Todo.get(Todo.title == "Apprendre COBOL")
TodoTag.create(todo= todo_cobol, tag= tag_urgent)
except IntegrityError as error:
print(error)

36
Semaine_07/Jour_05/orm_peewee/uv.lock generated Normal file
View File

@@ -0,0 +1,36 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "orm-peewee"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "peewee" },
{ name = "pymysql" },
]
[package.metadata]
requires-dist = [
{ name = "peewee", specifier = ">=4.0.2" },
{ name = "pymysql", specifier = ">=1.1.2" },
]
[[package]]
name = "peewee"
version = "4.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/9b/3439dcc3ed5138eb26f28fc208f958ca97b831f5f898b26d5354302e5df4/peewee-4.0.2.tar.gz", hash = "sha256:fd5d026ce7787c6cd3a84316e665a76b72c9c4e87322598c413f44604fa6c38d", size = 714081, upload-time = "2026-03-15T15:46:30.049Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/8e/943f57ce32eb005c7037110a759e2ebfb22e467a9a0efcb6d516c5bf00c6/peewee-4.0.2-py3-none-any.whl", hash = "sha256:86d5d16bcda5bbe017a108f6efc57abaac8d89277915541904542df9d2a7f25d", size = 143344, upload-time = "2026-03-15T15:46:28.778Z" },
]
[[package]]
name = "pymysql"
version = "1.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f5/ae/1fe3fcd9f959efa0ebe200b8de88b5a5ce3e767e38c7ac32fb179f16a388/pymysql-1.1.2.tar.gz", hash = "sha256:4961d3e165614ae65014e361811a724e2044ad3ea3739de9903ae7c21f539f03", size = 48258, upload-time = "2025-08-24T12:55:55.146Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/4c/ad33b92b9864cbde84f259d5df035a6447f91891f5be77788e2a3892bce3/pymysql-1.1.2-py3-none-any.whl", hash = "sha256:e6b1d89711dd51f8f74b1631fe08f039e7d76cf67a42a323d3178f0f25762ed9", size = 45300, upload-time = "2025-08-24T12:55:53.394Z" },
]