2017-08-07 178 views
1

我上,我需要根据另一列SQL查询中使用列一个公式来计算值

以下规定的公式计算值的请求的工作是我的表:

enter image description here

我需要编写查询以获取将基于FORMULA列的值。例如,我需要得到作为

enter image description here

由于公式可以是任何东西,包括我的专栏PRICESIZE的,我怎么写的查询来实现这一目标?

+4

没有简单的方法来做到这一点。一种方法是使用游标和动态SQL。 –

+0

更新期间为什么不在表中将值设置为计算列?如果更新发生不在SQL中 – ASpirin

+0

即使在SQL中,例如onupdate触发器也可以运行动态sql来计算值并放入列 – ASpirin

回答

1

另一个相对容易做的选择是使用CLR。您可以利用DataTable的计算方法在C#中提供简单的一行代码。

[Microsoft.SqlServer.Server.SqlFunction] 
public static double Evaluate(SqlString expression) 
{ 
    return double.Parse((new DataTable()).Compute(expression.ToString(), "").ToString()); 
} 

然后将组件添加到SQL Server和创建包装函数:

CREATE FUNCTION [dbo].[Evaluate](@expression [nvarchar](4000)) 
RETURNS [float] WITH EXECUTE AS CALLER 
AS 
EXTERNAL NAME [YourAssemblyName].[YourClassName].[Evaluate] 
GO 

现在你可以调用该函数作为一个简单的select语句的一部分:

SELECT itemid, price, size, formula, 
dbo.Evaluate(REPLACE(REPLACE(formula, 'PRICE', FORMAT(price,'0.00')), 
'SIZE', FORMAT(size, '0'))) as calcvalue FROM YourTable 
+0

解决方案为我工作..仍然不确定表现 – Rohaan

+0

很高兴有帮助。根据我的经验,CLR函数非常快,但是我从来不需要在桌面上使用超过60-70,000条记录,所以我真的不想说最快的解决方案。我恐怕我非常喜欢这所学校“不修补,什么都不坏”。如果我找到适合我的解决方案,我倾向于不去寻找另一个:-) –

0

假设你需要使用的公式取决于在列如值:大小时

select price, size, when size= 2 then (price*1.2)/size 
      when size= 3 then price/size 
      end my_calc 
    from my_table 
+0

我的公式可以是指定以外的任何值。 – Rohaan

+0

你有一个标准的公式?那么你可以你可以分类你的标准..并按照建议操作.. othewise你可以存储你的公式(sql抱怨),并分配代码使用dinamic sql – scaisEdge

+0

没有任何具体的标准。 – Rohaan

2

动态查询(唯一)的路要走,它并不复杂,你可以使用的情况下:

DECLARE @query NVARCHAR(MAX) = ''; 

SELECT @query = @query + ' 
UNION 
SELECT ItemID, Price, Size, Formula, ' + Formula + ' AS CalcValue FROM YourTable WHERE Formula = ''' + Formula + ''' ' 
FROM YourTable; 
SET @query = STUFF(@query,1,8,''); 

PRINT @query; 

EXEC (@query); 

SQLFiddle DEMO

但你必须知道如何容易出错,这是。如果公式列的值无效公式查询中断。

编辑:与UNION,而不是出现在多个行

EDIT2UNION ALL因为同一个公式的打算:B计划 - 而不是运行一堆相同的选择查询,并作出不同的结果的,最好使在开始不同的公式:

DECLARE @query NVARCHAR(MAX) = ''; 

WITH CTE_DistinctFormulas AS 
(
    SELECT DISTINCT Formula FROM YourTable 
) 
SELECT @query = @query + ' 
UNION ALL 
SELECT ItemID, Price, Size, Formula, ' + Formula + ' AS CalcValue FROM YourTable WHERE Formula = ''' + Formula + ''' ' 
FROM CTE_DistinctFormulas; 
SET @query = STUFF(@query,1,12,''); 

PRINT @query; 

EXEC (@query); 

SQLFiddle DEMO 2 - added few more rows

0

我做与此类似的东西,如果你在一个较小的操作池中玩,这并不难。我去了一个系列,我有X和Y列和一个操作员。然后,我在做出确定操作员并基于此操作执行逻辑的陈述时做了一个大案例。你可能不得不稍微改变你的结构。问题的核心是SQL是一个基于结果集的引擎,所以任何需要执行操作来确定动态的东西都会变慢。EG:

DECLARE @Formula TABLE 
(
    FormulaId INT IDENTITY 
, FormulaName VARCHAR(128) 
, Operator VARCHAR(4) 
); 

DECLARE @Values TABLE 
( 
    ValueId INT IDENTITY 
, FormulaId INT 
, Price MONEY 
, Size INT 
) 

INSERT INTO @Formula (FormulaName, Operator) 
VALUES ('Simple Addition', '+'), ('Simple Subtraction', '-'), ('Simple Multiplication', '*'), ('Simple Division', '/'), ('Squared', '^2'), ('Grow by 20 percent then Multiply', '20%*') 

INSERT INTO @Values (FormulaId, Price, Size) 
VALUES (1, 10, 5),(2, 10, 5),(3, 10, 5),(4, 10, 5),(5, 10, 5),(6, 10, 5),(1, 16, 12),(6, 124, 254); 

Select * 
From @Values 

SELECT 
    f.FormulaId 
, f.FormulaName 
, v.ValueId 
, Price 
, Operator 
, Size 
, CASE WHEN Operator = '+' THEN Price + Size 
     WHEN Operator = '-' THEN Price - Size 
     WHEN Operator = '*' THEN Price * Size 
     WHEN Operator = '/' THEN Price/Size 
     WHEN Operator = '^2' THEN Price * Price 
     WHEN OPerator = '20%*' THEN (Price * 1.20) * Size 
     END AS Output 
FROM @Values v 
    INNER JOIN @Formula f ON f.FormulaId = v.FormulaId 

用这种方法我的操作实际上只是一个指针引用到具有一个操作符是真正为所有意图和目的只是我用我的case语句令牌另一个表。你甚至可以将这个潜在的复杂化,如果你想做多次传递,你可以添加一个'组'列和一个'序列'并且一个接一个地完成。这取决于你的'公式'变得多么困难。因为如果进入频繁更改频繁更改的3个或4个变量,则可能需要执行动态SQL。但是,如果他们只是一些事情,那应该不那么难。请记住,这种方法的缺点在于,它在某个级别上很难编码,而且灵活性强,参数可以反复应用这个公式。