PG Day France 2019 : Merveilleux SQL - Lætitia AVROT
PG Day France le 19 juin 2019 @ Université Lumière Lyon2 https://www.pgday.fr
Un grand bravo à Laetitia Avrot !
La documentation du merveilleux langage SQL sur la merveilleuse machine IBM i !!!
Une histoire de Composants/Composés...
create table piece(
piece dec(5, 0) primary key,
libelle varchar(100));
create table compo(
cpse dec(5, 0) not null references piece,
cpsant dec (5, 0) not null references piece,
note varchar(100),
constraint Compo_pas_doublon_cpse_cpsant unique(cpse, cpsant));
with compo2 (niveau2, cpse2, cpsant2, note2) as
(select 1 , cpse, cpsant, note from compo where cpse = 1
union all
select niveau2 + 1 , cpse, cpsant, note
from compo2 join compo on compo2.cpsant2 = cpse
where niveau2 < 9)
search depth first by cpsant2 set col
cycle cpse2 set boucle to '1' default '0'
select niveau2, cpse2, cpsant2 , note2, sant.libelle, se.libelle, boucle
from compo2 left join piece sant on cpse2 = sant.piece
left join piece se on cpsant2 = se.piece
order by col;
"NIV2" "CPSE2" "CPSANT2" "LIBELLE" "LIBELLE" "BOUCLE"
1 1 4 "velo" "cadre" "0"
2 4 8 "cadre" "selle" "0"
2 4 5 "cadre" "fourche" "0"
2 4 6 "cadre" "guidon" "0"
3 6 7 "guidon" "sonnette" "0"
2 4 12 "cadre" "phare av" "0"
3 12 14 "phare av" "ampoule" "0"
2 4 13 "cadre" "phare ar" "0"
3 13 14 "phare ar" "ampoule" "0"
1 1 2 "velo" "roue av" "0"
2 2 10 "roue avant" "jante" "0"
2 2 11 "roue avant" "pneu" "0"
1 1 3 "velo" "roue ar" "0"
2 3 10 "roue ar" "jante" "0"
2 3 11 "roue ar" "pneu" "0"
select * from sysibm.sysdummy1 where (1, 2, 3 ) = (1, 2, 3) ; -- true
a1=b1 and a2=b2 and a3=b3
select * from sysibm.sysdummy1 where (1, 2, 3 ) = (1, 2, 4) ; -- false
select * from sysibm.sysdummy1 where (1, 2, 3 ) != (1, 2, 4) ; -- true
a1!=b1 or a2!=b2 or a3!=b3
select * from sysibm.sysdummy1 where (1, 2, 3 ) != (1, 2, 3) ; -- false
-- values : to create a table on the fly !
select * from test10 where (num1,num2, num3) in
(values( 1, 2, 3), (3, 4, 4));
select * from (values ( 1, 2, 3), (3, 4, 4)) as t;
values ( 1, 2, 3), (3, 4, 4);
values 123, 456, 789;
insert into test10
values (5, 5, 5), (6, 5, 4), (7, 4, 1), (2, 4, 8), (3, 6, 9);
create or replace function milan/fmr040 (p_mois dec(2))
returns table (mois dec(2), code dec(8), codcli char(8))
specific milan/fmr040
return select t1.mois, t1.code, t2.codcli
from
fmr015p as t0 join fichier2 as t2 on t0.codcli = t2.codcli
join fichier1 as t1 on t2.code = t1.code
where t1.mois = p_mois
order by t0.codcli, t2.code;
select * from table (fmr040(7)) as t1 order by codcli;
create or replace procedure milan/fmr050 (in p_mois dec(2))
specific milan/fmr050
dynamic result sets 1
set option dbgview = *source
b1:begin
declare c1 cursor with return for
select t1.mois, t1.code, t2.codcli
from
fmr015p as t0 join fichier2 as t2 on t0.codcli = t2.codcli
join fichier1 as t1 on t2.code = t1.code
where t1.mois = p_mois
order by t0.codcli, t2.code;
open c1;
return;
end b1;
call fmr050(7);
Voir Récupération d'un Result Set en Rpg
Il arrive qu'une table, qui devrait être unique, ne le soit que très modérément...
Ceci pose des problèmes lors d'éventuelles jointures : les lignes se multiplient !
Dans d'autre configuration, une non-unicité peut se terminer en plantage de la requête.
create table pays (pays_id char (3), libelle varchar (99));
-- On a oublié la clé primaire... Et il y a des doublons sur le pays !
create table personne(
personne_id dec(3, 0) primary key generated always as identity,
nom varchar(50),
pays_naiss char(3));
select * from personne left join pays on pays_naiss = pays_id;
-- Lignes dupliquées par la jointure !
-- Comment riposter :
select personne_id, nom, pays_naiss, (select libelle from pays b where a.pays_naiss = b.pays_id fetch first row only) as libelle from personne a;
-- par une judicieuse sous-requête scalaire de type full select, les lignes en trop sont évitées grace à "fetch first row only".
with pays_unique ( pays_id, libelle) as
(select pays_id, (select libelle from pays b where a.pays_id = b.pays_id fetch first row only) from pays a group by pays_id)
select * from personne left join pays_unique on pays_naiss = pays_id;
-- autre possibilité, la table mal gaulée est raffinée dans une CTE, ce qui permet son utilisation dans le join qui suit.
create view pays_uv (pays_id, libelle) as
(select pays_id, (select libelle from pays b where a.pays_id = b.pays_id fetch first row only) from pays a group by pays_id);
-- nous pouvons aussi créer une vue, qui sera utilisée en place de la table bancale.
select * from personne left join pays_uv on pays_naiss = pays_id;
create table pays_umqt (pays_id, libelle) as
(select pays_id, (select libelle from pays b where a.pays_id = b.pays_id fetch first row only) from pays a group by pays_id)
data initially immediate
refresh deferred
maintained by user;
-- nous pouvons aussi créer une materialized query table.
select * from personne left join pays_umqt on pays_naiss = pays_id;
-- Autres solutions bienvenues !
Dans une procédure ou fonction Sql,
il arrive que l'on ait un petit bout de code qui se répète à différents endroit :-((
En Rpg, on le collerai vite fait bien fait dans une fonction interne ou dans un sous-programme (exsr begsr endsr).
L'exemple en SQL PL ci-dessous simule - me semble t-il - un bon vieux sous-programme ;-))
Est-ce abuser des handlers !?
create or replace function milan / test
(p_zn1 dec(7), p_zn2 dec(7))
returns dec(7)
language sql
deterministic
no external action
specific milan / test
set option dbgview = *source
begin
declare zn3w dec(7) default 0;
declare iw dec(7) default 0;
declare exsr1w condition for '70001';
declare continue handler for exsr1w -- Attn : SubRoutine !
begin
set zn3w = zn3w + p_zn1;
set zn3w = zn3w + 1;
end;
bb:loop -- ceci est une boucle
set iw = iw + 1;
if iw > p_zn2
then
leave BB; -- Qu'il est triste de quitter Brigitte Bardot
end if;
signal exsr1w; -- Sorte d'Exsr... cf. en tête de programme
end loop;
return zn3w;
end;
-- Pour tester la fonction précédente :
values test(15, 15);