dev sql
authorJulien Moutinho <julm+LesQuatreRoux@sourcephile.fr>
Tue, 29 Apr 2025 02:36:00 +0000 (04:36 +0200)
committerJulien Moutinho <julm+LesQuatreRoux@sourcephile.fr>
Tue, 29 Apr 2025 02:36:00 +0000 (04:36 +0200)
26 files changed:
.gitignore [new file with mode: 0644]
data/Abonnement.csv
data/Ingrédient.csv
data/Panier.csv
data/Prix.csv [new file with mode: 0644]
data/Produit.dsv [deleted file]
data/Vente.csv
flake.nix
server.properties
sql/constraints.sql [new file with mode: 0644]
sql/dev.sql [new file with mode: 0644]
sql/export.sql
sql/import.sql
sql/init.sql
sql/init/Abonnement.sql
sql/init/Client.sql
sql/init/Facture.sql
sql/init/Ingrédient.sql
sql/init/Panier.sql
sql/init/Prix.sql [new file with mode: 0644]
sql/init/Produit.sql
sql/init/Stock.sql
sql/init/Vente.sql
sql/note.sql [new file with mode: 0644]
sql/recursive.sql [new file with mode: 0644]
sql/show.sql [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..a2d48ed
--- /dev/null
@@ -0,0 +1 @@
+hsqldb
index a98c6ca427a49041757cd1cc061460f2af7ac43c..032f00c46ef8ba2a6a5e735ed83d11ca2bff3678 100644 (file)
@@ -2,4 +2,4 @@
 "0"|"0"|"0"|"2"|"10"|"1.000"
 "1"|"1"|"1"|"2"|"14"|"2.000"
 "2"|"2"|"3"|"5"|"16"|"4.000"
-"3"|"0"|"2"|"3"|"11"|"1.000"
+"3"|"0"|"2"|"2"|"11"|"1.000"
index c1087494db9e08028ea626d67701d31283cd935a..9624c41cc25cb01599ec82b35149e3edde81fc8b 100644 (file)
@@ -1,2 +1,2 @@
 "ID"|"PRODUIT"|"CONSO"|"QUANTITÉ"
-"1"|"0"|"2"|"1.000"
+"2"|"31"|"3"|"23.000"
index 686b94ad1502a35880c3721262e84d3695eeedb0..266f6eda3661c6b165d9b874f33a8e5829a536f9 100644 (file)
@@ -4,4 +4,3 @@
 "2"|"2025-04-10 00:00:00"|"2"|
 "3"|"2025-04-14 00:00:00"|"0"|
 "4"|"2025-04-14 00:00:00"|"1"|
-"5"|"2025-04-08 00:00:00"|"0"|
diff --git a/data/Prix.csv b/data/Prix.csv
new file mode 100644 (file)
index 0000000..9979c44
--- /dev/null
@@ -0,0 +1,12 @@
+"ID"|"DATE"|"PRODUIT"|"EUROS"
+"0"|"2025-04-01 00:00:00"|"0"|"42.00"
+"1"|"2025-04-01 00:00:00"|"1"|"2.00"
+"2"|"2025-04-01 00:00:00"|"2"|"4.00"
+"3"|"2025-04-01 00:00:00"|"3"|"89.00"
+"4"|"2025-04-01 00:00:00"|"4"|"8.00"
+"5"|"2025-04-01 00:00:00"|"5"|"7.00"
+"6"|"2025-04-01 00:00:00"|"6"|"39.00"
+"7"|"2025-04-17 00:00:00"|"0"|"32.00"
+"8"|"2025-04-26 00:00:00"|"2"|"84.00"
+"9"|"2025-04-28 00:00:00"|"0"|"23.00"
+"10"|"2025-04-29 00:00:00"|"0"|"23.00"
diff --git a/data/Produit.dsv b/data/Produit.dsv
deleted file mode 100644 (file)
index e69de29..0000000
index c44ab316afffac5df23736751f9c66396ba86d6f..fe11f442c23737e2c667df0084abccf43ffce130 100644 (file)
@@ -1,7 +1,8 @@
 "ID"|"PRODUIT"|"QUANTITÉ"|"PANIER"
 "0"|"10"|"1.000"|"0"
 "1"|"14"|"2.000"|"1"
-"2"|"16"|"4.000"|"2"
-"3"|"10"|"1.000"|"3"
-"4"|"14"|"2.000"|"4"
-"5"|"11"|"1.000"|"5"
+"2"|"11"|"1.000"|"0"
+"3"|"16"|"4.000"|"2"
+"4"|"10"|"1.000"|"3"
+"5"|"14"|"2.000"|"4"
+"6"|"11"|"1.000"|"3"
index 69fac7727d77e72603df876b1c7958cbc9c4f8ce..e01da9c18853fef295bc71d7112020de36345911 100644 (file)
--- a/flake.nix
+++ b/flake.nix
@@ -84,6 +84,7 @@
               #odbcinst -q -d -n SQLite3
               #odbcinst -q -s -h
               #odbcinst -q -s -n ${database}
+              nix build -o hsqldb ${pkgs.hsqldb}
               set +x
               echo "You may now launch runServer"
             '' # + checks.${system}.git-hooks-check.shellHook
index 54c8db0c775b193ac077fc8a26f03658cdb3b459..bf524aa0844db81e1033e015b9566faa2d0bbab1 100644 (file)
@@ -1,4 +1,2 @@
-server.database.0=file:LesQuatreRoux;default_schema=true;default_table_type=cached;shutdown=false;sql.lowercase_ident=true
+server.database.0=file:LesQuatreRoux;default_schema=true;default_table_type=cached;shutdown=false;get_column_name=false;sql.lowercase_ident=true
 server.dbname.0=LesQuatreRoux
-server.database.1=file:Test;default_schema=true;shutdown=false;default_table_type=cached;get_column_name=false;sql.lowercase_ident=true
-server.dbname.1=test
diff --git a/sql/constraints.sql b/sql/constraints.sql
new file mode 100644 (file)
index 0000000..c2f542b
--- /dev/null
@@ -0,0 +1,8 @@
+\p SYSTEM_PRIMARYKEYS
+SELECT * FROM INFORMATION_SCHEMA.SYSTEM_PRIMARYKEYS;
+
+--\p SYSTEM_TABLES
+--SELECT TABLE_NAME FROM INFORMATION_SCHEMA.SYSTEM_TABLES;
+
+\p SYSTEM_CROSSREFERENCE
+SELECT * FROM INFORMATION_SCHEMA.SYSTEM_CROSSREFERENCE;
diff --git a/sql/dev.sql b/sql/dev.sql
new file mode 100644 (file)
index 0000000..012acd2
--- /dev/null
@@ -0,0 +1,78 @@
+\.
+--TRUNCATE TABLE "Vente";
+--TRUNCATE TABLE "Panier";
+DROP PROCEDURE insertVente IF EXISTS CASCADE;
+CREATE PROCEDURE insertVente
+  ( IN venteDate DATE
+  , IN venteClient INTEGER
+  , IN venteProduit INTEGER
+  , IN venteQuantité DECIMAL
+  )
+  MODIFIES SQL DATA
+  BEGIN ATOMIC
+    DECLARE panierID INTEGER DEFAULT NULL;
+    DECLARE venteID INTEGER DEFAULT NULL;
+
+    -- CorrectnessNote: seule la date et le client
+    -- font partie des critères pour décider
+    -- si le panier existe déjà où non.
+    SET panierID = SELECT ID FROM "Panier"
+                             WHERE "Panier".date = venteDate
+                             AND   "Panier".client = venteClient;
+    IF panierID IS NULL
+    THEN
+      INSERT INTO "Panier"(date, client)
+             VALUES (venteDate, venteClient);
+      SET panierID = IDENTITY();
+    END IF;
+
+    -- CorrectnessNote: la quantité ne fait pas partie des critères
+    -- pour décider si la vente existe déjà ou non.
+    SET venteID = SELECT ID FROM "Vente"
+                            WHERE "Vente".panier = panierID
+                            AND   "Vente".produit = venteProduit;
+    IF venteID IS NULL
+    THEN
+      INSERT INTO "Vente"(panier, produit, quantité)
+             VALUES (panierID, venteProduit, venteQuantité);
+    END IF;
+  END
+.;
+
+DROP PROCEDURE insertVentesParAbonnement IF EXISTS;
+CREATE PROCEDURE insertVentesParAbonnement(IN finalDate DATE)
+  MODIFIES SQL DATA
+  BEGIN ATOMIC
+    -- ExplanationNote: gère chaque jour l'un après l'autre.
+    for_days:
+    FOR SELECT day
+      FROM UNNEST (SEQUENCE_ARRAY(DATE '2025-04-07', finalDate, 1 DAY))
+             WITH ORDINALITY as T(day, I)
+    DO
+      -- ExplanationNote: pour un jour donné,
+      -- gère chaque abonnement l'un après l'autre.
+      for_abos:
+      FOR SELECT ID as aboID
+               , client as aboClient
+               , produit as aboProduit
+               , quantité as aboQuantité
+               , période as aboP
+            FROM "Abonnement"
+            JOIN "Période" ON "Période".ID = "Abonnement".période
+                   AND "Période".nom = DAYNAME(day)
+      DO
+        CALL insertVente(day, aboClient, aboProduit, aboQuantité);
+      END FOR for_abos;
+    END FOR for_days;
+  END;
+.;
+
+CALL insertVentesParAbonnement(DATE '2025-04-07' + 7 DAY);
+
+\i sql/show.sql
+
+--call prix_à_date(CURRENT_DATE);
+select "Prod".nom_complet, date, euros
+from table (prix_à_date(CURRENT_DATE)) as PD
+join table (choisirUnProduit()) as "Prod" ON "Prod".ID = produit
+;
index 7ed0f8fc2e5e3acdd999448b38a9e08af07601e7..85c94fd5e359ae4ee42c35d91ba5850c7b8f72c2 100644 (file)
@@ -25,3 +25,5 @@ SET SCHEMA B;
 \xq SELECT * FROM "Panier"
 * *DSV_TARGET_FILE = data/Vente.csv
 \xq SELECT * FROM "Vente"
+* *DSV_TARGET_FILE = data/Prix.csv
+\xq SELECT * FROM "Prix"
index 43fd3362ae10b8da144cea556314db79df8301a1..f7a065a9bba5047ae97d4d4442d9d608fe80f82f 100644 (file)
@@ -12,9 +12,9 @@ SET SCHEMA B;
 * *DSV_TARGET_TABLE = "Facture"
 \mq data/Facture.csv
 
-\p Importing Panier
-* *DSV_TARGET_TABLE = "Panier"
-\mq data/Panier.csv
+--\p Importing Panier
+--* *DSV_TARGET_TABLE = "Panier"
+--\mq data/Panier.csv
 
 \p Importing Produit
 * *DSV_TARGET_TABLE = "Produit"
@@ -35,3 +35,7 @@ SET SCHEMA B;
 \p Importing Ingrédient
 * *DSV_TARGET_TABLE = "Ingrédient"
 \mq data/Ingrédient.csv
+
+\p Importing Prix
+* *DSV_TARGET_TABLE = "Prix"
+\mq data/Prix.csv
index 71e095085c7b2198263a0982e0b8508354633c3e..ea208382f5f50cfe385dbed210aa14531892136a 100644 (file)
@@ -3,10 +3,11 @@ ALTER CATALOG PUBLIC RENAME TO D;
 ALTER SCHEMA PUBLIC RENAME TO B;
 \c false
 SET DATABASE COLLATION "French";
-\p CREATE TABLE tmp
-DROP TABLE tmp IF EXISTS;
-CREATE TABLE tmp (ID INT);
-INSERT INTO tmp(ID) VALUES (0);
+SET DATABASE DEFAULT TABLE TYPE CACHED;
+--\p CREATE TABLE tmp
+--DROP TABLE tmp IF EXISTS;
+--CREATE TABLE tmp (ID INT);
+--INSERT INTO tmp(ID) VALUES (0);
 
 \i sql/init/Produit.sql
 \i sql/init/Ingrédient.sql
@@ -18,3 +19,4 @@ INSERT INTO tmp(ID) VALUES (0);
 \i sql/init/Panier.sql
 \i sql/init/Vente.sql
 \i sql/init/Stock.sql
+\i sql/init/Prix.sql
index 53c81dcdc0267db1f8ba1b8f11165aee3dec8896..2f3efc4040fd782e4a5ec8b316bcb1749645b4a0 100644 (file)
@@ -7,14 +7,20 @@ CREATE CACHED TABLE "Abonnement"
   , produit INTEGER NOT NULL
   , quantité DECIMAL(100,3) DEFAULT 1.000 NOT NULL
   , CONSTRAINT "PK_Abonnement" PRIMARY KEY(ID)
-  , CONSTRAINT "FK_Abonnement_client" FOREIGN KEY(client) REFERENCES "Client"(ID) ON DELETE CASCADE
+  , CONSTRAINT "FK_Abonnement_client"
+      FOREIGN KEY(client)
+      REFERENCES "Client"(ID)
+      ON DELETE CASCADE
+  , CONSTRAINT "FK_Abonnement_produit"
+      FOREIGN KEY(produit)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Abonnement_période"
+      FOREIGN KEY(période)
+      REFERENCES "Période"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Abonnement_lieu"
+      FOREIGN KEY(lieu)
+      REFERENCES "Lieu"(ID)
+      ON UPDATE CASCADE
   );
-ALTER TABLE "Abonnement"
-  ADD CONSTRAINT "FK_Abonnement_produit" FOREIGN KEY(produit) REFERENCES "Produit"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Abonnement"
-  ADD CONSTRAINT "FK_Abonnement_période" FOREIGN KEY(période) REFERENCES "Période"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Abonnement"
-  ADD CONSTRAINT "FK_Abonnement_lieu" FOREIGN KEY(lieu) REFERENCES "Lieu"(ID)
-  ON UPDATE CASCADE;
index 04b64355f4d53e6b3711653face730fba3253b5d..ac15229a6fb7ff135a0d82a672a4354b656bca3c 100644 (file)
@@ -10,3 +10,17 @@ CREATE CACHED TABLE "Client"
 ALTER TABLE "Client"
   ADD CONSTRAINT "FK_Client_lieu" FOREIGN KEY(lieu) REFERENCES "Lieu"(ID)
   ON UPDATE CASCADE;
+
+DROP FUNCTION choisirUnClient IF EXISTS CASCADE;
+CREATE FUNCTION choisirUnClient()
+  RETURNS TABLE(nom_complet VARCHAR(100), ID INTEGER)
+  READS SQL DATA
+  BEGIN ATOMIC
+    RETURN TABLE
+      (SELECT nom || ' (' || "Lieu".nom || ')' AS nom_complet
+             , ID
+      FROM "Client"
+      JOIN "Lieu" ON "Lieu".ID = "Client".lieu
+      );
+  END;
+.;
index 1b2d75b0b66fcd7cfb39f616de434fe75c804ed0..2aeda404a1ae5299ac4745e36bbc5bdde202e249 100644 (file)
@@ -1,6 +1,6 @@
 \p CREATE TABLE Facture
 CREATE CACHED TABLE "Facture"
   ( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL
-  , date INTEGER NOT NULL
+  , date DATE DEFAULT CURRENT_DATE NOT NULL
   , CONSTRAINT "PK_Facture" PRIMARY KEY(ID)
   );
index e9c714b0fa21468a9e255f148a4a71699b7c759d..d775a2791c89e3745e6077deae40a5a865c8af1e 100644 (file)
@@ -5,13 +5,16 @@ CREATE CACHED TABLE "Ingrédient"
   , conso INTEGER NOT NULL
   , quantité DECIMAL(100,3) DEFAULT 1.000 NOT NULL
   , CONSTRAINT "PK_Ingrédient" PRIMARY KEY(ID)
+  , CONSTRAINT "Un produit ne se liste pas lui-même comme consommation"
+      CHECK (produit != conso)
+  , CONSTRAINT "FK_Ingrédient_produit"
+      FOREIGN KEY(produit)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Ingrédient_conso"
+      FOREIGN KEY(conso)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
   );
 CREATE UNIQUE INDEX "Ingrédient_index_produit_et_conso"
   ON "Ingrédient"(produit,conso);
-ALTER TABLE "Ingrédient"
-  ADD  CONSTRAINT "Un produit ne se liste pas lui-même comme consommation"
-      CHECK (produit != conso)
-ALTER TABLE "Ingrédient" ADD CONSTRAINT "FK_Ingrédient_produit" FOREIGN KEY(produit) REFERENCES "Produit"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Ingrédient" ADD CONSTRAINT "FK_Ingrédient_conso" FOREIGN KEY(conso) REFERENCES "Produit"(ID)
-  ON UPDATE CASCADE;
index e9f82a37bd2092d78bf94af7d757f31cde43d13d..3d866ab938f818ad60c03d7a97d9518fb02b0f4c 100644 (file)
@@ -1,14 +1,16 @@
 \p CREATE TABLE Panier
 CREATE CACHED TABLE "Panier"
   ( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL
-  , date DATE NOT NULL
+  , date DATE DEFAULT CURRENT_DATE NOT NULL
   , client INTEGER NOT NULL
   , facture INTEGER
   , CONSTRAINT "PK_Panier" PRIMARY KEY(ID)
+  , CONSTRAINT "FK_Panier_facture"
+      FOREIGN KEY(facture)
+      REFERENCES "Facture"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Panier_client"
+      FOREIGN KEY(client)
+      REFERENCES "Client"(ID)
+      ON UPDATE CASCADE
   );
-ALTER TABLE "Panier"
-  ADD CONSTRAINT "FK_Panier_facture" FOREIGN KEY(facture) REFERENCES "Facture"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Panier"
-  ADD CONSTRAINT "FK_Panier_client" FOREIGN KEY(client) REFERENCES "Client"(ID)
-  ON UPDATE CASCADE;
diff --git a/sql/init/Prix.sql b/sql/init/Prix.sql
new file mode 100644 (file)
index 0000000..5f30315
--- /dev/null
@@ -0,0 +1,44 @@
+\p CREATE TABLE Prix
+CREATE CACHED TABLE "Prix"
+  ( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL
+  , date DATE DEFAULT CURRENT_DATE NOT NULL
+  , produit INTEGER NOT NULL
+  , euros DECIMAL(100,2) DEFAULT 0.00 NOT NULL
+  , CONSTRAINT "PK_Prix" PRIMARY KEY(ID)
+  , CONSTRAINT "FK_Prix_produit"
+      FOREIGN KEY(produit)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "La combinaison (produit, date) d'un prix doit être unique"
+      UNIQUE (produit, date)
+  );
+
+DROP FUNCTION produit_maxdate IF EXISTS CASCADE;
+CREATE FUNCTION produit_maxdate(IN at_date DATE)
+  RETURNS TABLE(produit INTEGER, max_date DATE)
+  READS SQL DATA
+  BEGIN ATOMIC
+    RETURN TABLE
+      (SELECT "Produit".ID as produit
+             , MAX( date ) as max_date
+          FROM "Prix"
+          JOIN "Produit" ON "Produit".ID = "Prix".produit
+          WHERE date <= at_date
+          GROUP BY "Produit".ID
+      );
+  END;
+.;
+
+DROP FUNCTION prix_à_date IF EXISTS CASCADE;
+CREATE FUNCTION prix_à_date(IN at_date DATE)
+  RETURNS TABLE(produit INTEGER, "DATE" DATE, euros DECIMAL)
+  READS SQL DATA
+  BEGIN ATOMIC
+    RETURN TABLE
+      (SELECT produit, date, euros
+         FROM TABLE (produit_maxdate(at_date)) as P
+         JOIN "Prix" ON "Prix".produit = P.produit
+                    AND "Prix".date = P.max_date
+      );
+  END;
+.;
index f3b713babad59bc444eea3806b6a0b1d85f60798..673fbb7c51a141d8af64f7ede25ec8e6abf2303c 100644 (file)
@@ -6,4 +6,23 @@ CREATE CACHED TABLE "Produit"
   , quantité DECIMAL(100,3) DEFAULT 1.000 NOT NULL
   , conditionnement VARCHAR(100)
   , CONSTRAINT "PK_Produit" PRIMARY KEY(ID)
+  , CONSTRAINT "La combinaison (nom, quantité, conditionnement) d'un produit doit être unique"
+      UNIQUE (nom, quantité, conditionnement)
   );
+
+DROP FUNCTION choisirUnProduit IF EXISTS CASCADE;
+CREATE FUNCTION choisirUnProduit()
+  RETURNS TABLE(nom_complet VARCHAR(100), ID INTEGER)
+  READS SQL DATA
+  BEGIN ATOMIC
+    RETURN TABLE
+      (SELECT nom || ' ('
+                  || RTRIM(RTRIM(TO_CHAR(quantité),'0'),'.')
+                  || nvl(unité,'')
+                  || ')'
+                  AS nom_complet
+            , ID
+      FROM "Produit"
+      );
+  END;
+.;
index a5455e33f66b646d303584bdd49cf94bf9fe3eec..536a5fe308f0b0df9b5d2a50f50baa6bf22bdb60 100644 (file)
@@ -5,10 +5,12 @@ CREATE CACHED TABLE "Stock"
   , produit INTEGER NOT NULL
   , quantité DECIMAL(100,3) DEFAULT 1.000 NOT NULL
   , CONSTRAINT "PK_Stock" PRIMARY KEY(ID)
+  , CONSTRAINT "FK_Stock_lieu"
+      FOREIGN KEY(lieu)
+      REFERENCES "Lieu"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Stock_produit"
+      FOREIGN KEY(produit)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
   );
-ALTER TABLE "Stock"
-  ADD CONSTRAINT "FK_Stock_lieu" FOREIGN KEY(lieu) REFERENCES "Lieu"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Stock"
-  ADD CONSTRAINT "FK_Stock_produit" FOREIGN KEY(produit) REFERENCES "Produit"(ID)
-  ON UPDATE CASCADE;
index 19435c1e08d230935005c0fd41226b84f3e24379..f5dcb324a70956ef20588bbfc7bd3a47e6f03272 100644 (file)
@@ -5,10 +5,12 @@ CREATE CACHED TABLE "Vente"
   , quantité DECIMAL(100,3) DEFAULT 1.000 NOT NULL
   , panier INTEGER NOT NULL
   , CONSTRAINT "PK_Vente" PRIMARY KEY(ID)
+  , CONSTRAINT "FK_Vente_produit"
+      FOREIGN KEY(produit)
+      REFERENCES "Produit"(ID)
+      ON UPDATE CASCADE
+  , CONSTRAINT "FK_Vente_panier"
+      FOREIGN KEY(panier)
+      REFERENCES "Panier"(ID)
+      ON UPDATE CASCADE
   );
-ALTER TABLE "Vente"
-  ADD CONSTRAINT "FK_Vente_produit" FOREIGN KEY(produit) REFERENCES "Produit"(ID)
-  ON UPDATE CASCADE;
-ALTER TABLE "Vente"
-  ADD CONSTRAINT "FK_Vente_panier" FOREIGN KEY(panier) REFERENCES "Panier"(ID)
-  ON UPDATE CASCADE;
diff --git a/sql/note.sql b/sql/note.sql
new file mode 100644 (file)
index 0000000..bb62eba
--- /dev/null
@@ -0,0 +1,76 @@
+NEXT_DAY(CURRENT_DATE, 'WEDNESDAY')
+DROP TYPE SYS_REFCURSOR CASCADE;
+CREATE TYPE SYS_REFCURSOR AS INT;
+
+SET DATABASE REFERENTIAL INTEGRITY FALSE;
+SET DATABASE REFERENTIAL INTEGRITY TRUE;
+SELECT * FROM UNNEST(SEQUENCE_ARRAY(CURRENT_DATE, CURRENT_DATE + 6 DAY, 1 DAY)) WITH ORDINALITY AS T(D, I);
+
+CREATE FUNCTION an_hour_before (t TIMESTAMP)
+  RETURNS TIMESTAMP
+  RETURN t - 1 HOUR
+
+CREATE PROCEDURE delete_extra_customers(INOUT val_p INT, IN lastname_p VARCHAR(20))
+  MODIFIES SQL DATA
+  BEGIN ATOMIC
+    SET val_p = 0;
+    for_label: FOR SELECT * FROM customers WHERE lastname = lastname_p DO
+      IF val_p > 0 THEN
+      DELETE FROM customers WHERE customers.id = id;
+      END IF;
+      SET val_p = val_p + 1;
+    END FOR for_label;
+  END
+
+-- DECLARE my_ver INTEGER DEFAULT 2;
+-- loop_label: WHILE my_var < 20 DO
+--   INSERT INTO CUSTOMERS VALUES (DEFAULT, my_var);
+--   SET my_var = my_var + 1;
+--   -- LEAVE can be used to break the loop
+--   IF my_var = 15 THEN LEAVE loop_label; END IF;
+-- END WHILE loop_label;
+
+-- Array of dates
+SELECT *
+FROM UNNEST(SEQUENCE_ARRAY(DATE '2025-04-07', CURRENT_DATE + 7 DAY, 1 DAY))
+       WITH ORDINALITY AS T(D, I);
+DECLARE LOCAL NAMES TABLE test_retval (x INT);
+
+
+
+
+
+CREATE TABLE customers(id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, firstname VARCHAR(50), lastname VARCHAR(50), added TIMESTAMP);
+
+CREATE TABLE addresses(id INTEGER GENERATED BY DEFAULT AS IDENTITY, customerid INTEGER, address VARCHAR(50));
+
+ALTER TABLE addresses ADD CONSTRAINT fk_addr FOREIGN KEY(customerid) REFERENCES customers(id);
+
+\.
+DROP PROCEDURE new_customer IF EXISTS;
+CREATE PROCEDURE new_customer(firstname VARCHAR(50), lastname VARCHAR(50))
+   MODIFIES SQL DATA DYNAMIC RESULT SETS 1
+   BEGIN ATOMIC
+     DECLARE result CURSOR FOR SELECT * FROM CUSTOMERS WHERE ID = IDENTITY();
+     INSERT INTO CUSTOMERS VALUES (DEFAULT, firstname, lastname, CURRENT_TIMESTAMP);
+     OPEN result;
+   END
+.;
+
+--CREATE VIEW Prix
+--CREATE DOMAIN valid_string AS VARCHAR(20) DEFAULT 'NO VALUE' CHECK (VALUE IS NOT NULL AND CHARACTER_LENGTH(VALUE) > 2)
+--select "Prix".*, P.*
+--  FROM TABLE (produit_maxdate(CURRENT_DATE)) as P
+--  JOIN "Prix" ON "Prix".ID = P.ID
+--   AND "Prix".date = P.max_date
+--;
+-- SELECT "PRICES".*
+-- FROM ( SELECT "PID", MAX( "D" ) AS "MD"
+--         FROM "PRICES" JOIN "PROD" ON "PROD"."ID" = "PRICES"."PID"
+--         WHERE "EX" = FALSE AND "D" <= COALESCE ( :pDate, CURRENT_DATE )
+--         GROUP BY "PID" ) AS "X"
+-- JOIN "PRICES" ON "PRICES"."PID" = "X"."PID"
+--  AND "PRICES"."D" = "X"."MD"
+
+--SET retval = SEQUENCE_ARRAY(DATE '2025-04-07', DATE '2025-04-17', 1 DAY);
+--select count(*) from information_schema.columns where table_name='LOB_IDS' and table_schema='SYSTEM_LOBS';
diff --git a/sql/recursive.sql b/sql/recursive.sql
new file mode 100644 (file)
index 0000000..9d4b4ed
--- /dev/null
@@ -0,0 +1,27 @@
+
+
+You can create recursive procedures following the same guidelines. First create the procedure with a simple body that throws an exception. You need to specify the SPECIFIC name of the procedure:
+
+CREATE PROCEDURE updateFolderTotals(IN p_id VARCHAR(32), IN p_size BIGINT, IN p_files   INT, IN p_folders INT) 
+  SPECIFIC updateFolderTotals_1 MODIFIES SQL DATA 
+  SIGNAL SQLSTATE '45000'
+
+Then alter the created procedure with the full body:
+
+ALTER SPECIFIC ROUTINE updateFolderTotals_1
+  BEGIN ATOMIC  
+  DECLARE l_parentid VARCHAR(32); 
+  UPDATE folders  
+  SET tot_files = tot_files + p_files, 
+    tot_size = tot_size + p_size , 
+    tot_folders = tot_folders + p_folders 
+  WHERE id = p_id;  
+
+  SELECT parentid INTO l_parentid FROM folders WHERE id = p_id; 
+
+  IF (l_parentid IS NOT NULL) THEN 
+    CALL updateFolderTotals(l_parentid,p_size,p_files,p_folders); 
+  END IF; 
+END; 
+
+
diff --git a/sql/show.sql b/sql/show.sql
new file mode 100644 (file)
index 0000000..019da43
--- /dev/null
@@ -0,0 +1,44 @@
+\p Table Abonnement
+SELECT ID as abonnement_id,
+  "Client".nom as client_nom,
+  "Lieu".nom as lieu_nom,
+  "Période".nom as période_nom,
+  "Produit".nom as produit_nom,
+  quantité
+  FROM "Abonnement"
+  JOIN "Client" ON "Client".ID = client
+  JOIN "Lieu" ON "Lieu".ID = lieu
+  JOIN "Période" ON "Période".ID = période
+  JOIN "Produit" ON "Produit".ID = produit;
+\p .
+\p Table Panier
+SELECT ID as panier_id,
+       TO_CHAR(date, 'YYYY-MM-DD') as panier_date,
+       "Client".nom as panier_client_nom,
+       "Lieu".nom as panier_lieu_nom
+  FROM "Panier"
+  JOIN "Client" ON "Client".ID = client
+  JOIN "Lieu" ON "Lieu".ID = "Client".lieu
+  ;
+\p .
+\p Table Vente
+SELECT ID as vente_id,
+       "Panier".ID as panier_id,
+       TO_CHAR("Panier".date, 'YYYY-MM-DD') as vente_panier_date,
+       "Client".nom as vente_panier_client_nom,
+       "Produit".nom as vente_produit,
+       "Vente".quantité as vente_quantité
+  FROM "Vente"
+  JOIN "Panier" ON "Panier".ID = panier
+  JOIN "Produit" ON "Produit".ID = produit
+  JOIN "Client" ON "Client".ID = client
+  ;
+\p .
+\p Table Prix
+SELECT ID as prix_id,
+       TO_CHAR("Prix".date, 'YYYY-MM-DD') as prix_date,
+       "Produit".nom as prix_produit,
+       euros as prix_euros
+  FROM "Prix"
+  JOIN "Produit" ON "Produit".ID = produit
+  ;