SQL Query使用列作为计算值的公式

时间:2017-08-07 12:21:55

标签: sql sql-server-2008 tsql

我正在处理一项请求,我需要根据另一列中指定的公式计算值

以下是我的表格:

enter image description here

我需要编写查询以获取将基于FORMULA列的值。例如,我需要结果

enter image description here

由于公式可以是由我的列PRICESIZE组成的任何内容,如何编写查询来实现此目标?

4 个答案:

答案 0 :(得分: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代替UNION ALL,因为同一个公式出现在多行

edit2 :计划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

答案 1 :(得分:1)

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

Dim Excel
Dim xlBook
Dim xlSheet
Dim xyz

Set Excel = CreateObject("Excel.Application")
Set xlBook = Excel.Workbooks.Add
Set xlSheet = xlBook.Worksheets(1)
   xlSheet.Application.Visible = 1

xlSheet.Application.Visible = True
xlSheet.Application.Cells(1, 1).Value = "This is column A, row 1"
xlSheet.Application.Cells(1, 2).Value = 200
xlSheet.Application.Cells(1, 3).Value = 0.1
xlSheet.Application.Cells(2, 2).Value = "=B1-190-C1"

Wscript.Echo "Like this?"
Wscript.Echo xlSheet.Application.Cells(1, 3)
Wscript.Echo xlSheet.Application.Range("B2")

xlSheet.Application.Range("B5").GoalSeek Goal=0, ChangingCell=xlSheet.Application.Range("B2")


xlSheet.SaveAs "C:\TEST.XLS"
xlSheet.Application.Quit
Set xlSheet = Nothing

然后将程序集添加到SQL Server并创建包装函数:

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

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

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

答案 2 :(得分:0)

假设您需要使用的公式取决于列中的值,例如:大小,您可以使用案例

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

答案 3 :(得分: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语句的所有意图和目的。你甚至可以将它复合化,如果你想要多次通过,你可以添加一个' Group'列和'序列'并一个接一个地做。这取决于你的公式'成为。因为如果经常更改操作符而导致频繁更改的3个或4个变量,那么您可能希望执行动态sql。但如果它们只是一些东西,那应该不会那么难。请记住,这种方法的缺点是它在某个级别上是硬编码的,但是灵活的参数可以反复应用这个公式。