2011-04-22 1 views
4

J'ai une table des paiements, avec des valeurs positives et négatives (à savoir, les captures et les crédits). Je dois identifier les points où nous avons reçu un montant net positif, depuis le dernier montant net positif. Par exemple, si le client effectue ces paiements et reçoit ces crédits:Existe-t-il un meilleur moyen d'identifier les limites d'intervalle de temps d'un motif en série?

01/01 $100 <- 
02/01 -$100 
03/01 -$100 
04/01 $100 
05/01 $100 
06/01 $100 <- 

... alors les points seront 01/01 et 06/01: à partir de 02/01 par 04/01, ils ont solde négatif, et à partir du 05/01, ils ont un solde nul.

Mon approche actuelle commence par la construction d'une liste des dates de fin de toutes les dates avec une capture, calcule alors une date de début pour chacun d'entre eux, et calcule enfin les captures nettes pour ces périodes:

Start  End  NetCaptures 
1900/01/01 2011/01/01 $100 
2011/01/02 2011/04/01 -$100 
2011/04/02 2011/05/01 $100 
2011/05/02 2011/06/01 $100 

I puis supprimez les enregistrements avec une NetCaptures de 0 $ ou moins, recalculez les dates de début, recalculez les captures nettes et répétez jusqu'à ce qu'il n'y ait plus d'enregistrements à supprimer, en laissant ceci.

Start  End  NetCaptures 
1900/01/01 2011/01/01 $100 
2011/01/02 2011/06/01 $100 

Y a-t-il une meilleure façon de procéder? Une utilisation intelligente des expressions d'analyse? Cela se rapproche de RBAR. En pratique, il fonctionne rapidement (dix minutes pour les enregistrements 500K, contre 1,5 avant de commencer à comptabiliser les crédits de cette manière).

* RÉSULTAT *

Alors que Microsoft prend en charge une fonction totale de roulement gracieux, en utilisant cette pensée j'ai fini avec le code comme ceci: calculer toutes les captures, calculer le fonctionnement total à chacun et supprimez ceux où il existe un enregistrement antérieur dont le total cumulé est égal ou supérieur.

CREATE TABLE #Sequences 
    (
    OrderID INT NOT NULL, 
    Sequence INT NOT NULL, 
    PRIMARY KEY (OrderID, Sequence), 
    StartDate DATE NOT NULL DEFAULT '1900-01-01', 
    EndDate DATE NOT NULL, 
    CapturesThisPeriod DECIMAL(18, 2) NOT NULL DEFAULT 0.00, 
    ) 
INSERT INTO #Sequences (OrderID, Sequence, EndDate) 
    SELECT OrderID, ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY DateReceived), DateReceived 
    FROM Receipts 
    WHERE Amount > 0.00 

/* Calculate the start date for each period */ 
UPDATE S 
SET StartDate = DATEADD(D, 1, Prev.EndDate) 
FROM 
    #Sequences AS S 
    INNER JOIN #Sequences AS Prev ON S.OrderID = Prev.OrderID AND Prev.Sequence = S.Sequence - 1 

/* Calculate the cumulative total for each period */ 
UPDATE M 
SET CumulativeReceipts = R.Receipts 
FROM 
    #Sequences AS M 
    INNER JOIN  
     (
     SELECT 
      M.OrderID, M.Sequence, SUM(R.Amount) AS Receipts 
     FROM 
      #Sequences AS M 
      INNER JOIN Receipts AS R ON M.OrderID = R.OrderID AND R.DateReceived <= M.EndDate 
     GROUP BY 
      M.OrderID, M.Sequence 
     ) AS R ON M.OrderID = R.OrderID AND M.Sequence = R.Sequence 

/* Delete sequences with do not represent net positive receipts */ 
DELETE FROM M 
FROM #Sequences AS M 
WHERE EXISTS (SELECT * FROM #Sequences AS Prev WHERE M.OrderID = Prev.OrderID AND Prev.Sequence < M.Sequence AND Prev.CumulativeReceipts >= M.CumulativeReceipts) 

/* Recalculate sequence numbers and dates */ 
UPDATE S SET Sequence = NewSequence FROM (SELECT Sequence, ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY Sequence) AS NewSequence FROM #Sequences) AS S 
UPDATE S 
SET StartDate = DATEADD(D, 1, Prev.EndDate) 
FROM 
    #Sequences AS S 
    INNER JOIN #Sequences AS Prev ON S.OrderID = Prev.OrderID AND Prev.Sequence = S.Sequence - 1 
    END 

/* Calculate net captures per period, and continue with analysis */ 
+2

Recherche autour de « somme courante »; par exemple, http://explainextended.com/2010/01/22/sql-server-running-totals/ – Andomar

+0

Voulez-vous dire que vous voulez que les pics locaux d'une courbe? c'est à dire. chaque fois que la courbe dépasse le maximum précédent? Ou êtes-vous intéressé lorsque la courbe dépasse zéro? –

+0

@Andomar, je crois que c'est exactement ce dont j'ai besoin! Si vous voulez ajouter cela comme réponse, je le marquerai comme accepté. Je savais que ça devait être un moyen plus simple. Je posterai mon code quand il sera implémenté. @Lasse, basé sur un total cumulé, je cherche tous les points au-dessus de zéro. J'étais bloqué sur la mise en œuvre des valeurs par unité, je ne pensais pas commencer avec le total cumulé et le backtrack à partir de là. –

Répondre

Questions connexes