Question

J'ai besoin des conseils pour lutter contre une requête. Je peux gérer cela dans une application frontale, cependant, en raison de la conception, je dois inplement cela dans l'arrière-plan. Je les


CREATE TABLE [dbo].[openitems](
    [id] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [type] [char](5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [date] [smalldatetime] NULL,
    [amount] [decimal](9, 2) NULL,
    [daysOpen] [smallint] NULL,
    [balance] [decimal](9, 2) NULL
) ON [PRIMARY]




insert into openitems values('A12399','INV','2008-12-05',491.96,123)

insert into openitems values('A12399','INV','2008-12-12',4911.37,116)

insert into openitems values('A12399','INV','2008-12-05',3457.69,109)

Le tableau ci-dessus ont toutes les factures ouvertes pour un client. Je dois demander un paiement à ces factures à partir de la facture la plus ancienne (colonne daysOpen dans le tableau). Donc, si j'ai un paiement 550.00 $, je vais d'abord l'appliquer à la facture avec 123 daysOld, c'est 491,96 $ - 500 $ (ce qui laisse 8,04 $ à appliquer à la facture suivante ... et ainsi de suite), puis mettre à jour cet enregistrement (solde colonne du tableau) à 0,00 et passer à la suivante et appliquer le reste. Ce serait 4911,37 $ - 8,04 $, ce qui laisserait 4903,33 $. Comme il n'y a pas de solde restant à appliquer, les sorties en boucle.

La colonne équilibre doit maintenant

0
4903.33
3457.69

Note: Je dois faire cela pour tous les clients dans un tableau (environ 10 000). Un client a une moyenne d'environ 20 factures ouvertes.

Merci

Était-ce utile?

La solution

Considérez ce qui suit:

un paiement soit applique intégralement à un équilibre, applique en partie à un équilibre ou surpaye un équilibre.

Maintenant, imaginez que nous pourrions trouver, tout solde, le solde cumulé des factures à ce jour. Plutôt que d'imaginer que, faisons-le:

create view cumulative_balance as
select a.*, 
  (select sum( balance ) 
  from openitems b 
  where b.id = a.id and b.type = a.type and a.daysOpen >= a.daysOpen)
  as cumulative_balance
from openitems a;

Maintenant, nous pouvons trouver le premier solde cumulé inférieur ou égal au paiement, pour tout id et le type, et magasin qui, et daysOpen et solde cumulatif des variables du serveur.

Ensuite, nous mettons à jour tous les openItems avec cet identifiant et le type, où daysOpen <= la valeur que nous avons obtenu, le réglage de tous les soldes à zéro.

Ensuite, nous trouvons le premier solde non nul de cet identifiant et le type, et définissez son équilibre comme son équilibre - (paiement - le solde cumulé nous stockons). s'il y a un trop-perçu, cet équilibre sera correctement négatif.

Avec la requête correcte, vous serez en mesure de faire la recherche et première mise à jour dans une instruction.

Il y a deux problèmes. La première est que vous ne pouvez pas déterminer, de deux ou plusieurs alances avec le même identifiant et le type et daysOpen, qui doit être payé en premier. Ajout d'un uniques id à votre table servirait de départager ces cas.

La deuxième est la nécessité de sauvegarder le solde cumulatif pour l'utiliser dans la requête pour la deuxième mise à jour. si vous avez conçu correctement votre table, avec une colonne pour INVOICE_AMOUNT qui n'a pas été mis à jour par des paiements, et une colonne de paiement qui a été, cela résoudrait votre problème.

Un refactoring encore mieux serait d'avoir deux tables, une pour les factures et un paiement. Alors une vue pourrait tout faire tout le travail, en comparant les soldes cumulatifs aux paiements cumulatifs, la production d'une liste des soldes ou les trop-payés impayés

En fait, j'ai conçu un tel système pour une importante société de garantie hypothécaire avec les initiales FM. Il était un peu plus compliqué que ce que vous avez, en ce que les soldes ont été calculés à partir d'un certain nombre de formules de montants et pourcentages, et plusieurs payeurs (en fait, les assureurs, ce fut pour les prêts hypothécaires qui avaient un défaut de remboursement) devait être facturé en ordre prescrit selon d'autres règles, par hypothèque defauted.

Tout cela a été fait en vue, avec une courte (ligne 100 ou donc) procédure stockée essentiellement fait ce que je l'ai indiqué ci-dessus: utilisé une vue qui a ordonné la facturation des factures par ces règles, les paiements demandés (dans le vue), le calcul de ce que des paiements supplémentaires à facturer à quelle date à laquelle l'assureur. La procédure stockée puis des factures générées pour que la date actuelle (qui date actuelle pourrait être définie, en utilisant à nouveau une vue, à une date à des fins de test).

(L'ironie est que j'avais pris le travail onteh promesse que j'obtiendrais d'écrire C ++, le seul C ++ que j'ai écrit utilisé les API Oracle et Sybase C pour transférer des données du système Oracle Sybase un.)

Autres conseils

Cela devrait le faire. J'ai déclaré une variable locale, mais vous pouvez faire qu'un paramètre à partir d'une procédure stockée. J'ai aussi ajouté un invoice_id à la table pour identifier les factures depuis id et la date ne semblent pas être unique.

DECLARE
    @paid_amount DECIMAL(9, 2)

SET @paid_amount = 500

UPDATE
    OI
SET
    balance =
            CASE
                WHEN @paid_amount - SQ.running_total > balance THEN 0
                ELSE balance - (@paid_amount - SQ.running_total)
            END
FROM
    dbo.OpenItems OI
INNER JOIN (
    SELECT
        I1.id,
        I1.invoice_id,
        I1.date,
        ISNULL(SUM(I2.amount), 0) AS running_total
    FROM
        OpenItems I1
    LEFT OUTER JOIN OpenItems I2 ON
        I2.id = I1.id AND
        I2.type = 'INV' AND
        I2.daysopen > I1.daysopen
    GROUP BY
        I1.id,
        I1.invoice_id,
        I1.date
) AS SQ ON
    SQ.id = OI.id AND
    SQ.invoice_id = OI.invoice_id
WHERE
    @paid_amount > SQ.running_total

À moins que c'est un effort d'une fois ...

On dirait que cela est logique et buisness appartient dans votre couche métier de votre application.

Vous devez utiliser deux curseurs et deux boucles imbriquées. (Cela peut être un peu lent)

Un pour lire tous les paiements - Je suppose que Client, Montant

Ensuite, pour chaque client de créer un autre curseur pour les éléments ouverts.

La première boucle lire les paiements jusqu'à ce que fait

Dans cette boucle ouvrir un nouveau curseur pour les éléments ouverts du client triées par la plus ancienne.

boucle à travers chaque élément ouvert et appliquer les paiements que vous avez décrit

Ensuite, obtenir le paiement suivant.

Répéter jusqu'à ce qu'il n'y plus de paiements.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top