OVH Cloud OVH Cloud

Problème de conception de requête

5 réponses
Avatar
TedIF
Bonsoir,

je sèche sur une requête.

Soit une table :

CREATE TABLE [FDG_MODIFICATION] (
[ID_MODIF_FDG] [int] IDENTITY (1, 1) NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATE] NOT NULL ,
[MT_ORIGINE_COT_A] [MONTANT] NULL ,
[C_MODIF_FDG] [int] NOT NULL ,

...

Je recherche à obtenir pour chaque ID_COTISATION, l' ID_MODIF_FDG ayant
la plus petite DT_MODIF_FDG par ID_COTISATION.
Sachant qu'il peut y avoir plusieurs dates identiques par ID_COTISATION
et dans ce cas on doit prendre en priorité la ligne ayant C_MODIF_FDG =
5 si elle existe.
Cerise sur le gateau s'il y a deux fois C_MODIF_FDG = 5 on ne
sélectionne aucune ligne pour cet ID_COTISATION.

La vitesse d'exécution n'est pas une priorité.

Merci d'avance pour votre aide.

--

Dominique

5 réponses

Avatar
Steve Kass
Ted,

Essayer cette requête (pas testée). La dernière condition dépend si
la cerise - deux 5 pour l'ID_COTISATION à la même date minimum,
ou deux 5 n'importe quand?

select
ID_COTISATION,
ID_MODIF_FDG
from (
select
ID_COTISATION,
ID_MODIF_FDG
from FDG_MODIFICATION as M1
where ID_MODIF_FDG = (
select top 1 ID_MODIF_FDG
from FDG_MODIFICATION as M2
where M2.ID_COTISATION = M1.ID_COTISATION
order by
DT_MODIF_FDG, -- la date la plus petite
CASE WHEN C_MODIF_FDG = 5 THEN 0 ELSE 1 END, -- priorité des 5
ID_MODIF_FDG -- au cas de deux 5, choisir l'ID_MODIF_FDG la plus
petite
) as T1
where not exists ( -- encore un "5" pour cet ID_COTISATION, au cas que
C_MODIF_FDG = 5
select * from FDG_MODIFICATION as T2
where T2.ID_COTISATION = T1.ID_COTISATION
and T2.C_MODIF_FDG = 5
and T1.C_MODIF_FDG = 5
and T2.ID_COTISATION > T1.ID_COTISATION
-- and T2.DT_MODIF_FDG = T1.DT_MODIF_FDG
-- aucune ligne si les deux 5 n'ont pas la même date?
)

La vitesse est question des données et des indices. Si la clé primaire
est ID_MODIF_FDG, je suggère un index nonclustered sur
(ID_COTISATION, DT_MODIF_FDG,C_MODIF_FDG)
ou clustered sur (ID_COTISATION, DT_MODIF_FDG).

Steve Kass
Drew University


TedIF wrote:

Bonsoir,

je sèche sur une requête.

Soit une table :

CREATE TABLE [FDG_MODIFICATION] (
[ID_MODIF_FDG] [int] IDENTITY (1, 1) NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATE] NOT NULL ,
[MT_ORIGINE_COT_A] [MONTANT] NULL ,
[C_MODIF_FDG] [int] NOT NULL ,

...

Je recherche à obtenir pour chaque ID_COTISATION, l' ID_MODIF_FDG
ayant la plus petite DT_MODIF_FDG par ID_COTISATION.
Sachant qu'il peut y avoir plusieurs dates identiques par
ID_COTISATION et dans ce cas on doit prendre en priorité la ligne
ayant C_MODIF_FDG = 5 si elle existe.
Cerise sur le gateau s'il y a deux fois C_MODIF_FDG = 5 on ne
sélectionne aucune ligne pour cet ID_COTISATION.

La vitesse d'exécution n'est pas une priorité.

Merci d'avance pour votre aide.



Avatar
TedIF
Steve Kass vient de nous annoncer :
Ted,

La dernière condition dépend si
la cerise - deux 5 pour l'ID_COTISATION à la même date minimum,
ou deux 5 n'importe quand?



S'il existe deux codes 5 pour la date la plus ancienne on n'en prends
aucune.


select
ID_COTISATION,
ID_MODIF_FDG
from (
select
ID_COTISATION,
ID_MODIF_FDG
from FDG_MODIFICATION as M1
where ID_MODIF_FDG = (
select top 1 ID_MODIF_FDG
from FDG_MODIFICATION as M2
where M2.ID_COTISATION = M1.ID_COTISATION
order by
DT_MODIF_FDG, -- la date la plus petite
CASE WHEN C_MODIF_FDG = 5 THEN 0 ELSE 1 END, -- priorité des 5
ID_MODIF_FDG -- au cas de deux 5, choisir l'ID_MODIF_FDG la plus
petite
) as T1
where not exists ( -- encore un "5" pour cet ID_COTISATION, au cas que
C_MODIF_FDG = 5
select * from FDG_MODIFICATION as T2
where T2.ID_COTISATION = T1.ID_COTISATION
and T2.C_MODIF_FDG = 5
and T1.C_MODIF_FDG = 5
and T2.ID_COTISATION > T1.ID_COTISATION
-- and T2.DT_MODIF_FDG = T1.DT_MODIF_FDG
-- aucune ligne si les deux 5 n'ont pas la même date?
)




Merci pour ton aide.

J'ai modifié ta requête comme suit pour permettre son exécution. Mais
elle me retourne beaucoup trop de lignes. Peut-être ai je male corrigé.

select
ID_COTISATION,
ID_MODIF_FDG
from (
select
ID_COTISATION,
ID_MODIF_FDG,
C_MODIF_FDG,
DT_MODIF_FDG
from FDG_MODIFICATION M1
where ID_MODIF_FDG = (
select top 1 ID_MODIF_FDG
from FDG_MODIFICATION M2
where M2.ID_COTISATION = M1.ID_COTISATION
order by
DT_MODIF_FDG, -- la date la plus petite
CASE WHEN C_MODIF_FDG = 5 THEN 0 ELSE 1 END, -- priorité des 5
ID_MODIF_FDG -- au cas de deux 5, choisir l'ID_MODIF_FDG la plus
petite
)
) T1

where not exists ( -- encore un "5" pour cet ID_COTISATION, au cas que
C_MODIF_FDG = 5
select * from FDG_MODIFICATION T2
where T2.ID_COTISATION = T1.ID_COTISATION
and T2.C_MODIF_FDG = 5
and T1.C_MODIF_FDG = 5
and T2.ID_COTISATION > T1.ID_COTISATION
-- and T2.DT_MODIF_FDG = T1.DT_MODIF_FDG
-- aucune ligne si les deux 5 n'ont pas la même date?
)

--

Dominique
Avatar
Fred BROUARD
Voici comment procéder :

CREATE TABLE FDG_MODIFICATION
( [ID_MODIF_FDG] [int] NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATETIME] NOT NULL ,
[C_MODIF_FDG] [int] NOT NULL)

INSERT INTO FDG_MODIFICATION VALUES (1, 10, '2005-01-18', 2)
INSERT INTO FDG_MODIFICATION VALUES (2, 10, '2005-01-15', 7)
INSERT INTO FDG_MODIFICATION VALUES (3, 10, '2005-01-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (4, 20, '2005-02-20', 2)
INSERT INTO FDG_MODIFICATION VALUES (5, 20, '2005-02-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (6, 20, '2005-02-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (7, 20, '2005-02-15', 3)
INSERT INTO FDG_MODIFICATION VALUES (8, 30, '2005-02-10', 3)
INSERT INTO FDG_MODIFICATION VALUES (9, 30, '2005-02-18', 3)


/* Je recherche à obtenir : pour chaque ID_COTISATION,
l' ID_MODIF_FDG ayant la plus petite DT_MODIF_FDG par ID_COTISATION. */

SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- --------------------- -----------
2 10 2005-01-15 7
3 10 2005-01-15 5
5 20 2005-02-15 5
6 20 2005-02-15 5
7 20 2005-02-15 3
8 30 2005-02-10 3




/* S'il y a plusieurs dates identiques par ID_COTISATION dans ce cas
on doit prendre en priorité la ligne ayant C_MODIF_FDG = 5 si elle existe. */


SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)
-- ajout de la préférence pour 5
AND C_MODIF_FDG = COALESCE((SELECT DISTINCT C_MODIF_FDG
FROM FDG_MODIFICATION M3
WHERE M3.ID_COTISATION = M1.ID_COTISATION
AND C_MODIF_FDG = 5) , C_MODIF_FDG)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- ------------------ -----------
3 10 2005-01-15 5
5 20 2005-02-15 5
6 20 2005-02-15 5
8 30 2005-02-10 3


/* S'il y a deux fois C_MODIF_FDG = 5 on ne sélectionne aucune ligne pour cet
ID_COTISATION. */

SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)
AND C_MODIF_FDG = COALESCE((SELECT DISTINCT C_MODIF_FDG
FROM FDG_MODIFICATION M3
WHERE M3.ID_COTISATION = M1.ID_COTISATION
AND C_MODIF_FDG = 5) , C_MODIF_FDG)
-- unicité de la valeur 5 dans C_MODIF_FDG
AND NOT EXISTS (SELECT *
FROM FDG_MODIFICATION M4
WHERE M4.ID_COTISATION = M1.ID_COTISATION
AND M4.C_MODIF_FDG = M1.C_MODIF_FDG
AND C_MODIF_FDG = 5
AND M4.ID_MODIF_FDG <> M1.ID_MODIF_FDG)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- -------------------- -----------
3 10 2005-01-15 5
8 30 2005-02-10 3


Et pour apprendre les finesses de SQL, mes deux ouvrages "SQL Développement" et
"SQL" collection Synthex, pourrons t'aider !

A +


--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************


TedIF a écrit:
Bonsoir,

je sèche sur une requête.

Soit une table :

CREATE TABLE [FDG_MODIFICATION] (
[ID_MODIF_FDG] [int] IDENTITY (1, 1) NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATE] NOT NULL ,
[MT_ORIGINE_COT_A] [MONTANT] NULL ,
[C_MODIF_FDG] [int] NOT NULL ,

...

Je recherche à obtenir pour chaque ID_COTISATION, l' ID_MODIF_FDG ayant
la plus petite DT_MODIF_FDG par ID_COTISATION.
Sachant qu'il peut y avoir plusieurs dates identiques par ID_COTISATION
et dans ce cas on doit prendre en priorité la ligne ayant C_MODIF_FDG =
5 si elle existe.
Cerise sur le gateau s'il y a deux fois C_MODIF_FDG = 5 on ne
sélectionne aucune ligne pour cet ID_COTISATION.

La vitesse d'exécution n'est pas une priorité.

Merci d'avance pour votre aide.



Avatar
Fred BROUARD
Voici comment procéder :

CREATE TABLE FDG_MODIFICATION
( [ID_MODIF_FDG] [int] NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATETIME] NOT NULL ,
[C_MODIF_FDG] [int] NOT NULL)

INSERT INTO FDG_MODIFICATION VALUES (1, 10, '2005-01-18', 2)
INSERT INTO FDG_MODIFICATION VALUES (2, 10, '2005-01-15', 7)
INSERT INTO FDG_MODIFICATION VALUES (3, 10, '2005-01-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (4, 20, '2005-02-20', 2)
INSERT INTO FDG_MODIFICATION VALUES (5, 20, '2005-02-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (6, 20, '2005-02-15', 5)
INSERT INTO FDG_MODIFICATION VALUES (7, 20, '2005-02-15', 3)
INSERT INTO FDG_MODIFICATION VALUES (8, 30, '2005-02-10', 3)
INSERT INTO FDG_MODIFICATION VALUES (9, 30, '2005-02-18', 3)


/* Je recherche à obtenir : pour chaque ID_COTISATION,
l' ID_MODIF_FDG ayant la plus petite DT_MODIF_FDG par ID_COTISATION. */

SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- --------------------- -----------
2 10 2005-01-15 7
3 10 2005-01-15 5
5 20 2005-02-15 5
6 20 2005-02-15 5
7 20 2005-02-15 3
8 30 2005-02-10 3




/* S'il y a plusieurs dates identiques par ID_COTISATION dans ce cas
on doit prendre en priorité la ligne ayant C_MODIF_FDG = 5 si elle existe. */


SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)
-- ajout de la préférence pour 5
AND C_MODIF_FDG = COALESCE((SELECT DISTINCT C_MODIF_FDG
FROM FDG_MODIFICATION M3
WHERE M3.ID_COTISATION = M1.ID_COTISATION
AND C_MODIF_FDG = 5) , C_MODIF_FDG)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- ------------------ -----------
3 10 2005-01-15 5
5 20 2005-02-15 5
6 20 2005-02-15 5
8 30 2005-02-10 3


/* S'il y a deux fois C_MODIF_FDG = 5 on ne sélectionne aucune ligne pour cet
ID_COTISATION. */

SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)
AND C_MODIF_FDG = COALESCE((SELECT DISTINCT C_MODIF_FDG
FROM FDG_MODIFICATION M3
WHERE M3.ID_COTISATION = M1.ID_COTISATION
AND C_MODIF_FDG = 5) , C_MODIF_FDG)
-- unicité de la valeur 5 dans C_MODIF_FDG
AND NOT EXISTS (SELECT *
FROM FDG_MODIFICATION M4
WHERE M4.ID_COTISATION = M1.ID_COTISATION
AND M4.C_MODIF_FDG = M1.C_MODIF_FDG
AND C_MODIF_FDG = 5
AND M4.ID_MODIF_FDG <> M1.ID_MODIF_FDG)

ID_MODIF_FDG ID_COTISATION DT_MODIF_FDG C_MODIF_FDG
------------ ------------- -------------------- -----------
3 10 2005-01-15 5
8 30 2005-02-10 3


Et pour apprendre les finesses de SQL, mes deux ouvrages "SQL Développement" et
"SQL" collection Synthex, pourrons t'aider !

A +


--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************


TedIF a écrit:
Bonsoir,

je sèche sur une requête.

Soit une table :

CREATE TABLE [FDG_MODIFICATION] (
[ID_MODIF_FDG] [int] IDENTITY (1, 1) NOT NULL ,
[ID_COTISATION] [int] NOT NULL ,
[DT_MODIF_FDG] [DATE] NOT NULL ,
[MT_ORIGINE_COT_A] [MONTANT] NULL ,
[C_MODIF_FDG] [int] NOT NULL ,

...

Je recherche à obtenir pour chaque ID_COTISATION, l' ID_MODIF_FDG ayant
la plus petite DT_MODIF_FDG par ID_COTISATION.
Sachant qu'il peut y avoir plusieurs dates identiques par ID_COTISATION
et dans ce cas on doit prendre en priorité la ligne ayant C_MODIF_FDG =
5 si elle existe.
Cerise sur le gateau s'il y a deux fois C_MODIF_FDG = 5 on ne
sélectionne aucune ligne pour cet ID_COTISATION.

La vitesse d'exécution n'est pas une priorité.

Merci d'avance pour votre aide.



Avatar
TedIF
Fred BROUARD a utilisé son clavier pour écrire :

SELECT *
FROM FDG_MODIFICATION M1
WHERE DT_MODIF_FDG = (SELECT MIN(DT_MODIF_FDG)
FROM FDG_MODIFICATION M2
WHERE M2.ID_COTISATION = M1.ID_COTISATION)
AND C_MODIF_FDG = COALESCE((SELECT DISTINCT C_MODIF_FDG
FROM FDG_MODIFICATION M3
WHERE M3.ID_COTISATION = M1.ID_COTISATION
AND C_MODIF_FDG = 5) , C_MODIF_FDG)
-- unicité de la valeur 5 dans C_MODIF_FDG
AND NOT EXISTS (SELECT *
FROM FDG_MODIFICATION M4
WHERE M4.ID_COTISATION = M1.ID_COTISATION
AND M4.C_MODIF_FDG = M1.C_MODIF_FDG
AND C_MODIF_FDG = 5
AND M4.ID_MODIF_FDG <> M1.ID_MODIF_FDG)




Merci bien pour ton aide et bravo pour ta pédagogie.

--

Dominique