1
votes

SQL - Utilisation de LEAD pour sauter des lignes avec une certaine condition

Utilisation de SQL standard dans Google BigQuery.

J'ai une table avec 2 types de commande: A et B.

SELECT Id, Type,
    LEAD(OrderDate) OVER (PARTITION BY Id ORDER BY OrderDate)
FROM xxx

Pour chaque type de commande A, je souhaite déterminer quand la prochaine commande B était, en ignorant toutes les autres commandes A.

Donc, dans mes données d'exemple, si je souhaite renvoyer ce qui suit:

Id | Type | NextOrderBDate
--------------------------------
1  |  A   | 2019-03-04
4  |  A   | 2019-04-05
5  |  A   | 2019-04-05

J'ai obtenu le résultat de manière extrêmement inefficace en joignant 2 tables séparées de A et B l'une à l'autre - mais l'ensemble de données est très volumineux et il a fallu plus d'une heure pour s'exécuter.

Ce que j'essaie actuellement à faire est d'utiliser une instruction LEAD comme ceci:

Id | Type | OrderDate
-----------------
1  |  A   | 2019-03-01
2  |  B   | 2019-03-04
3  |  B   | 2019-03-04
4  |  A   | 2019-03-05
5  |  A   | 2019-03-06
6  |  B   | 2019-04-05

De toute évidence, le problème ici est qu'il retournera la date suivante, quel que soit le type de commande.

Je me demande si la clé pour faire cela est de déterminer le décalage correct dont chaque ligne a besoin pour MENER au prochain ordre de type B, et j'ai du mal à trouver une solution (propre) ici.

Merci à l'avance.


0 commentaires

3 Réponses :


0
votes

Vous pouvez utiliser une requête en ligne comme suit:

id | type | NextOrderBDate
-: | :--- | :-------------
 1 | A    | 2019-03-04    
 4 | A    | 2019-04-05    
 5 | A    | 2019-04-05    

Démo sur DB Fiddlde :

select
    id,
    type,
    (
        select min(OrderDate) 
        from mytable t1 
        where t1.Type = 'B' and t1.OrderDate >= t.OrderDate
    ) NextOrderBDate
from mytable t
where type = 'A'


0 commentaires

0
votes

Utilisez simplement un min cumulatif:

select t.*
from (select t.*,
             min(case when type = 'B' then orderdate end) over (order by orderdate) as next_b_orderdate
      from t
     ) t
where type = 'A';


0 commentaires

0
votes

@Gordon Linoff a raison sauf petit bug: la prochaine commande B doit être trouvée liée à chaque commande courante . Donc, la fenêtre de requête doit IMHO être adaptée de manière appropriée:

with t (id, type, orderdate) as (
  select 1  ,  'A'   , date '2019-03-01' union
  select 2  ,  'B'   , date '2019-03-04' union
  select 3  ,  'B'   , date '2019-03-04' union
  select 4  ,  'A'   , date '2019-03-05' union
  select 5  ,  'A'   , date '2019-03-06' union
  select 6  ,  'B'   , date '2019-04-05'
)
select t.*
from (select t.*,
             min(case when type = 'B' then orderdate end)
             over (order by orderdate 
                 rows between current row and unbounded following
             ) as next_b_orderdate
      from t
     ) t
where type = 'A';


0 commentaires