2 votes

Sélection de dates minimales, ou nulles en SQL

Il s'agit d'une simplification à outrance, mais.. :

J'ai un tableau qui ressemble à ce qui suit :

CREATE TABLE Table1
    ([ID] int, [USER] varchar(5), [DATE] date)
;

INSERT INTO Table1
    ([ID], [USER], [DATE])
VALUES
    (1, 'A', '2018-10-01'),
    (2, 'A', '2018-09-01'),
    (3, 'A', NULL),
    (4, 'B', '2018-05-03'),
    (5, 'B', '2017-04-01'),
    (6, 'C', NULL)
;

Et pour chaque utilisateur, je souhaite récupérer toute la ligne de détails dans laquelle se trouve le DATE est minime.

SELECT T.USER FROM TABLE1 T
WHERE T.DATE = (SELECT MIN(DATE) FROM TABLE1 T1 WHERE T1.USER = T.USER)

Le système fonctionne parfaitement, mais dans l'instance, aucune ligne n'est remplie. DATE il y aura une ligne avec un NULL comme la dernière ligne de mon tableau ci-dessus, que je souhaite également sélectionner.

Dans ce cas, mon résultat idéal est donc le suivant :

(2, 'A', '2018-09-01'),
(5, 'B', '2017-04-01'),
(6, 'C', NULL)

SQL fiddle : http://www.sqlfiddle.com/#!9/df42b5/6

Je pense qu'il est possible de faire quelque chose en utilisant une instruction EXCLUDE, mais cela devient rapidement complexe.

2voto

fa06 Points 13375

Vous pouvez essayer avec row_number()

démo

    select * from
    (select *, row_number() over(partition by [user] order by [user],case when 
     [date] is null then 0 else 1 end desc,[date]) as rn
     from Table1)x where rn=1

1voto

Zaynul Abadin Tuhin Points 12097

Utiliser l'union et la sous-requête connexe avec min() fonction

     CREATE TABLE Table1 (ID int, usr varchar(50), DATE1 date)
;

INSERT INTO Table1 VALUES
    (1, 'A', '2018-10-01'),
    (2, 'A', '2018-09-01'),
    (3, 'A', NULL),
    (4, 'B', '2018-05-03'),
    (5, 'B', '2017-04-01'),
    (6, 'C', NULL)
;

select * from Table1 t  where 
   DATE1= (select min(date1) from Table1 t1 where t1.usr=t.usr
         ) and date1 is not null
           union
select * from Table1 t where date1 is  null
and t.usr not in ( select usr from Table1 where date1 is not null)

DEMO

ID  usr     DATE1
2   A   01/09/2018 00:00:00
5   B   01/04/2017 00:00:00
6   C

0voto

Vladislav Points 126

Vous pouvez utiliser une expression de tableau commune :

;WITH chronology AS (
    SELECT 
        *,
        ROW_NUMBER() OVER (
            PARTITION BY [USER] 
            ORDER BY ISNULL([DATE], '2900-01-01') ASC
        ) Idx
    FROM TABLE1
)
SELECT ID, [USER], [DATE]  
FROM chronology
WHERE Idx=1;

L'utilisation d'un ETC dans cette solution simplifie la requête en améliorant sa lisibilité, sa maintenabilité et son extensibilité. En outre, je m'attends à ce que cette approche soit optimale en termes de performances.

0voto

Sorin G Points 11

Vous pouvez utiliser GROUP BY et JOIN pour obtenir les résultats souhaités.

select t.Id
    , x.[User]
    , x.[MinDate] as [Date]
from
(select [User]
   , min([Date]) as MinDate
from table1
group by [User]) x
   inner join table1 t on t.[User] = x.[User] and (t.[Date] = x.[MinDate] or x.[MinDate] is null)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X