2017-09-22 7 views
1

J'essaie de reconstruire mon entreprise kardex. J'ai besoin d'utiliser la "méthode du coût moyen" qui est supposée prendre en compte le coût moyen pour chaque transaction sur son datetime spécifique.Reconstruire l'entreprise kardex

J'ai une table simple avec toutes les transactions d'inventaire entrantes/sortantes (tous les mouvements).

Chaque transaction entrante (achats) est correctement tarifée parce que je prends le coût unitaire de sa facture correspondante.

Le problème: Toutes les transactions de vente (inventaire sortant) n'ont AUCUN coût unitaire (parce que j'ai besoin de reconstruire ces coûts). Je sais que je peux utiliser des curseurs, mais nous connaissons tous les problèmes de performance.

J'ai préparé une simple donnée pour mieux m'expliquer. S'il vous plaît noter que toutes les ventes (transactions sortantes) n'a pas de coût, et je pense que l'aide de simples fonctions fenêtrées ne va pas aider parce que chaque rangée dépend du calcul précédent. Donc, j'ai besoin d'un calcul basé sur le calcul précédent .. ??

DECLARE @Resultado TABLE (Row_ID BIGINT IDENTITY NOT NULL PRIMARY KEY, Inventory_Name VARCHAR(100), Transaction_Date DATETIME, DIRECTION BIT, Transaction_Name VARCHAR(100),Transaction_Quantity INT, Transaction_UnitCost NUMERIC(18,2), Transaction_Amount NUMERIC(18,2), AVERAGE_UNITCOST_AT_TRANSACTION_DATE NUMERIC(18,2)) 

INSERT INTO @Resultado (Inventory_Name , Transaction_Date , DIRECTION , Transaction_Name , Transaction_Quantity , Transaction_UnitCost, Transaction_Amount, AVERAGE_UNITCOST_AT_TRANSACTION_DATE) 
SELECT 'COMPUTER', '2017-01-01', 1, 'INCOMING PRODUCT; PRUCHASE', 100, 10, 100 * 10, 10 
UNION ALL SELECT 'COMPUTER', '2017-01-02', 1, 'INCOMING PRODUCT; PURCHASE', 105, 11, 105 * 11, 10.51 
UNION ALL SELECT 'COMPUTER', '2017-01-03', 1, 'INCOMING PRODUCT; PURCHASE', 110, 12, 110 * 12, 11.03 
UNION ALL SELECT 'COMPUTER', '2017-01-04', 0, 'OUTGOING PRODUCT; SALES', -200, NULL, NULL, NULL 
UNION ALL SELECT 'COMPUTER', '2017-01-05', 0, 'OUTGOING PRODUCT; SALES', -50, NULL, NULL, NULL 
UNION ALL SELECT 'COMPUTER', '2017-01-06', 1, 'INCOMING PRODUCT; PURCHASE', 110, 10, 110 * 10, NULL 
UNION ALL SELECT 'COMPUTER', '2017-01-07', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL 
UNION ALL SELECT 'COMPUTER', '2017-01-08', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL 
UNION ALL SELECT 'COMPUTER', '2017-01-09', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL 

SELECT * FROM @Resultado 
+0

J'ai oublié de mentionner que j'utilise Microsoft SQL Server 2012 Standard –

+1

Beau travail sur les données de test, Veuillez ajouter les résultats attendus sous forme de texte et expliquer avec lui – TheGameiswar

Répondre

1

Conseil: Il vous aurait été utile d'inclure les résultats attendus dans votre question.

Cette expression commune tableau (CTE) devrait démarrer:

with CTE as (
    select Row_Id, Inventory_Name, Transaction_Date, Direction, Transaction_Name, 
    Transaction_Quantity, Transaction_UnitCost, 
    Transaction_Quantity as QuantityOnHand, 
    Transaction_UnitCost as AverageUnitCost 
    from @Resultado 
    where Direction = 1 and Row_Id = 1 -- Starting condition for your single product sample data. 
    union all 
    select R.Row_ID, R.Inventory_Name, R.Transaction_Date, R.Direction, R.Transaction_Name, 
    R.Transaction_Quantity, R.Transaction_UnitCost, 
    -- The TransactionQuantity is already signed, so there is no need to multiple it by (Direction * 2 - 1) . 
    CTE.QuantityOnHand + R.Transaction_Quantity, 
    -- My accounting is pretty rusty, but this should do some sort of useful averaging. 
    Cast(case 
     when R.Direction = 0 then CTE.AverageUnitCost -- Sales don't affect the average unit cost. 
     else (CTE.AverageUnitCost * CTE.QuantityOnHand + R.Transaction_UnitCost * R.Transaction_Quantity)/
     (CTE.QuantityOnHand + R.Transaction_Quantity) end 
     as Numeric(18,2)) 
    from CTE inner join 
     @Resultado as R on R.Row_Id = CTE.Row_Id + 1 -- Row by row. 
    ) 
    select Row_Id, Inventory_Name, Transaction_Date, Direction, Transaction_Name, Transaction_Quantity, Transaction_UnitCost, 
    QuantityOnHand, AverageUnitCost 
    from CTE; 

Vous pouvez exécuter contre vous échantillons de données après l'ajout d'un point-virgule à la fin de votre déclaration select.

Les performances sont susceptibles d'être médiocres car vous devez démarrer les calculs à partir de la première ligne. L'ajout de colonnes pour gérer les QuantityOnHand et AveragreUnitCost vous permet de mettre à jour les données lorsque de nouvelles transactions se produisent, par ex. dans un déclencheur. (Notez que les mises à jour et les suppressions peuvent nécessiter un recalcul depuis le début du temps.)

Une solution plus moderne utiliserait Lead/Lag, mais il se trouve que je suis de retour à SQL Server 2008 R2.

+0

Je confirme que cette requête est la solution que je recherchais. Que vous beaucoup. J'ai fait quelques changements mineurs car je dois l'adapter à certains scénarios spécifiques dans ma base de données, mais cette requête a rendu tout cela possible. Encore merci! –

+0

@LuisGilbert Je suis content que cela vous a indiqué dans la direction d'écriture. Accepter des réponses fait partie de l'étiquette de StackOverflow. Voir [Comment fonctionne l'acceptation d'une réponse?] (Http://meta.stackoverflow.com/questions/5234/how-does-accepting-an-answer-work). – HABO

+0

Désolé. Je suis en train de poster des questions. Réponse acceptée. Merci encore! –