2013-05-12 55 views
1

我有一个含1000个产品的ProductTable。例如下面只是7个产品。产品1-5的数据通过脚本从源文件导入到表中。我将使用这些数据来计算其他产品的数据。如何用公式创建表来计算第二个表中的数据?

然后我有第二个表的公式来计算第一个表中的产品的数据。会有很多产品,每个产品都有一定的配方。例如下面是2个产品。 此表不使用数字,但链接到第一个表。数字是第一个表中的productsID。

第三张表格是为了清楚理解并显示如何进行计算。这不是一个理想的结果。结果将是这些计算的结果。 (对于ProductID6和year1999结果应该是3;对于productID6和year2001结果是1.75,等)

1

如何可以写一个存储过程捕捉这些式叉。所以基本上我想制定一种方法来存储计算产品的公式。而且,如果需要,可以更改公式并重新计算结果。

很高兴听到您的想法。

+0

因此,每个产品有5个输入行和两个输出行? – Paparazzi 2013-05-12 19:59:16

+0

没有。有超过1000种产品。但其中一些是通过脚本插入的,另一些是从第一个开始计算的。所以我想存储公式来计算这些产品。 – Almazini 2013-05-13 05:56:28

+0

每个产品都是独一无二的,但每年都在变化。想象一下食品价格:牛奶,面包,啤酒,奶酪和咖啡的价格。 – Almazini 2013-05-13 06:16:01

回答

2

也许有很多方法可以解决这个问题,但我会尝试创建一个将年份和ProductID作为参数并返回一个映射公式的缩放功能。

-- Assumption is a Product table structured like this: Product(ProductID INT, [1999] INT, [2000] INT, [2001] INT); 
CREATE FUNCTION dbo.MapFn(@Y INT, @ProductID INT) 
RETURNS VARCHAR(200) 
AS 
BEGIN 
    DECLARE @A VARCHAR(10), @B VARCHAR(10), @C VARCHAR(10); 
    DECLARE @pvt TABLE(ProductID INT, Yr INT, Qty VARCHAR(10)); 
    DECLARE @f VARCHAR(80); 

    INSERT @pvt 
    SELECT ProductID, Yr, Qty 
    FROM (
     SELECT ProductID, [1999], [2000], [2001] 
     FROM dbo.Product) p 
    UNPIVOT (
     Qty FOR Yr IN ([1999], [2000], [2001]) 
    ) AS u 
    WHERE Yr = @Y; 

    SELECT @f = formula FROM dbo.Formula WHERE ProductID = @ProductID 
    SELECT @A = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.A = p.ProductID; 
    SELECT @B = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.B = p.ProductID; 
    SELECT @C = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.C = p.ProductID; 

    RETURN REPLACE(REPLACE(REPLACE(@f,'A', ISNULL(CAST(@A AS VARCHAR(50)), '')), 'B', ISNULL(CAST(@B AS VARCHAR(50)), '')), 'C', ISNULL(CAST(@C AS VARCHAR(50)), '')); 
END 
GO 

此功能在UNPIVOT中的固定年份列表中很脆弱,但您可以通过向列表添加更多年份来解决此问题。

用法示例

CREATE TABLE dbo.Product(ProductID INT, [1999] INT, [2000] INT, [2001] INT); 
GO 
CREATE TABLE dbo.Formula(ProductID INT, formula VARCHAR(80), [A] INT, [B] INT, [C] INT); 
GO 

INSERT dbo.Product values(1,10,20,30) 
, (2,15,25,35) 
, (3,5,15,20) 
, (4,4,8,12) 
, (5,6,12,18) 
, (6,NULL,NULL,NULL) 
, (7,NULL,NULL,NULL); 

INSERT dbo.Formula VALUES(6,'A/B',2,3,NULL) 
, (7,'A/(B+C)',5,3,1); 
GO 

CREATE FUNCTION dbo.MapFn(@Y INT, @ProductID INT) 
RETURNS VARCHAR(200) 
AS 
BEGIN 
    DECLARE @A VARCHAR(10), @B VARCHAR(10), @C VARCHAR(10); 
    DECLARE @pvt TABLE(ProductID INT, Yr INT, Qty VARCHAR(10)); 
    DECLARE @f VARCHAR(80); 

    INSERT @pvt 
    SELECT ProductID, Yr, Qty 
    FROM (
     SELECT ProductID, [1999], [2000], [2001] 
     FROM dbo.Product) p 
    UNPIVOT (
     Qty FOR Yr IN ([1999], [2000], [2001]) 
    ) AS u 
    WHERE Yr = @Y; 

    SELECT @f = formula FROM dbo.Formula WHERE ProductID = @ProductID 
    SELECT @A = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.A = p.ProductID; 
    SELECT @B = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.B = p.ProductID; 
    SELECT @C = p.Qty + '.0' FROM @pvt p JOIN dbo.Formula f ON f.ProductID = @ProductID AND f.C = p.ProductID; 

    RETURN REPLACE(REPLACE(REPLACE(@f,'A', ISNULL(CAST(@A AS VARCHAR(50)), '')), 'B', ISNULL(CAST(@B AS VARCHAR(50)), '')), 'C', ISNULL(CAST(@C AS VARCHAR(50)), '')); 
END 
GO 

-- Cursor loop to evaluate formulas 
DECLARE @ProductID INT; 
DECLARE @fa NVARCHAR(80); 
DECLARE @fb NVARCHAR(80); 
DECLARE @fc NVARCHAR(80); 
DECLARE @sql NVARCHAR(160); 
DECLARE @A DECIMAL(10,2), @B DECIMAL(10,2), @C DECIMAL(10,2) 
DECLARE @resultSet TABLE(ProductID INT, [1999] DECIMAL(10,2), [2000] DECIMAL(10,2), [2001] DECIMAL(10,2)); 
DECLARE c CURSOR FOR 
    SELECT f.ProductID 
    , [1999] = dbo.MapFn(1999,f.ProductID) 
    , [2000] = dbo.MapFn(2000,f.ProductID) 
    , [2001] = dbo.MapFn(2001,f.ProductID) 
    FROM dbo.Formula f; 
OPEN c 
FETCH NEXT FROM c INTO @ProductID, @fa, @fb, @fc; 

WHILE @@FETCH_STATUS = 0 BEGIN 
    -- 1999 
    SET @sql = N'SELECT @out = '[email protected]; 
    EXECUTE sp_executesql @sql, @params = N'@out DECIMAL(10,2) OUTPUT', @out = @A OUTPUT; 

    -- 2000 
    SET @sql = N'SELECT @out = '[email protected]; 
    EXECUTE sp_executesql @sql, @params = N'@out DECIMAL(10,2) OUTPUT', @out = @B OUTPUT; 

    -- 2001 
    SET @sql = N'SELECT @out = '[email protected]; 
    EXECUTE sp_executesql @sql, @params = N'@out DECIMAL(10,2) OUTPUT', @out = @C OUTPUT; 

    INSERT @resultSet VALUES(@ProductID, @A, @B, @C); 
    FETCH NEXT FROM c INTO @ProductID, @fa, @fb, @fc; 
END 
SELECT * FROM @resultSet; 
CLOSE c; 
DEALLOCATE c; 

结果

ProductID 1999 2000 2001 
6   3.00 1.67 1.75 
7   0.40 0.34 0.36 
+0

感谢您的回答。请注意 - 第三张表格是为了清楚理解并仅显示计算应该如何完成。这不是一个理想的结果。结果将是这些计算的结果。 (对于ProductID6和year1999,结果应该为3;对于productID6和year2001,结果为1.75等) – Almazini 2013-05-13 06:00:41

+1

在这种情况下,需要使用游标来执行结果表中的公式,并使用输出参数调用sp_executesql。今天晚些时候我会在工作回来的时候探索这种可能性。 – 2013-05-13 13:36:43

+0

是的,我也在考虑游标。将等待你的答案约翰。 – Almazini 2013-05-13 13:44:04

相关问题