1
votes

Le moyen le plus rapide d'obtenir la première valeur non nulle d'une colonne dans une plage de dates dans SQL SERVER

Disons que j'ai la table SQL suivante (avec la clé primaire: date),

date      foo
-------- ----
20181001 NULL
20181101   10
20181201 NULL
20190101    1

Comment puis-je obtenir la première valeur non nulle de la colonne "foo", p>

  1. De la date "20181001" à "20181101"?
  2. De "20181201" à "20190101"?

Quelle fonction serveur SQL dois-je utiliser? Veuillez aider avec une fonction qui est plus rapide pour les grandes tables avec ~ 1 million d'enregistrements.


2 commentaires

Pouvez-vous montrer votre jeu de résultats attendu?


@dnoeth, a mis à jour la question avec des exemples d'entrée et de sortie.


5 Réponses :


3
votes

Nous pouvons utiliser ROW_NUMBER:

SELECT date, foo
FROM cte
WHERE rn = 1 AND date BETWEEN '20181001' AND '20181101';

Si vous souhaitez également limiter à une certaine plage de dates, ajoutez-le simplement au WHERE code> clause:

WITH cte AS (
    SELECT date, foo, ROW_NUMBER() OVER (ORDER BY date) rn
    FROM yourTable
    WHERE foo IS NOT NULL
)

SELECT date, foo
FROM cte
WHERE rn = 1;


2 commentaires

Comment puis-je faire fonctionner cela pour plusieurs valeurs? Veuillez vous référer à ma dernière modification.


J'ai retourné votre question à ce que vous aviez demandé au départ. Il est impoli et mauvais de faire sur ce site des changements importants à votre question après que de nombreux utilisateurs y ont déjà répondu. Si vous rencontrez un autre problème, vous pouvez poser une nouvelle question.



0
votes

Assurez-vous d'avoir un index d'index composite approprié sur

where foo is not null

et un filtre pour

(foo, date) 


0 commentaires

0
votes
SELECT TOP 1 date FROM table WHERE date IS NULL ORDER BY date DESC 
Select the null valued rows, order them desc by date, then select the top result. Should return the correct value.

0 commentaires

2
votes

La requête est simplement:

create index idx1 on mytable (date, foo);
create index idx2 on mytable (foo, date);

Ensuite, vous auriez un index pour un accès rapide. Je fournirais les deux suivants:

select top(1) foo
from mytable
where date between '20181001' and '20181101'
and foo is not null
order by date;

Le SGBD choisira l'un ou l'autre ou aucun d'entre eux en fonction de la sélectivité.


0 commentaires

2
votes

Je suppose que vous souhaitez commander les dates. Sinon, vous ne pourrez pas trouver la première valeur foo non nulle. Parce que le terme premier est relatif. Vous devez avoir une clause order by pour trouver la première valeur non nulle.

J'ai donné un exemple de code pour votre référence.

CREATE TABLE #test (datevalue DATE, foo INT);

CREATE CLUSTERED INDEX cix_test ON #test (datevalue);

INSERT INTO #test
VALUES ('20181001', NULL), ('20181101', 10), ('20181201', NULL), ('20190101', 1);

SELECT TOP 1 FIRST_VALUE(foo) OVER (
        ORDER BY datevalue
        )
FROM #test
WHERE datevalue BETWEEN '20181001'
        AND '20181101'
    AND foo IS NOT NULL;


4 commentaires

Comment puis-je faire en sorte que cela fonctionne pour plusieurs colonnes avec des valeurs de date différentes pour chaque colonne?


@deepak, comme l'a dit Tim Biegeleisen, je vous suggère de créer une autre question pour éviter toute confusion pour les futurs visiteurs de cette question


La requête semble inappropriée, car elle récupère cette première valeur multiple, car vous utilisez une fonction analytique. Ainsi, avec mille valeurs dans la plage de dates, vous obtenez un résultat de mille lignes affichant toutes la première valeur. Vous pouvez bien sûr appliquer DISTINCT sur le résultat, mais c'est un peu gênant à mon avis.


@ThorstenKettner, j'ai préparé la requête en fonction de l'ensemble de données d'entrée que l'utilisateur avait donné. Vous avez raison. J'ai mis à jour ma réponse.