SQL:是否可以在另一个字段中按公式计算字段

时间:2016-06-08 23:59:48

标签: sql sql-server

是否可以制作通过公式提交计算的表格或视图 ,在其他字段中指定为文本?

例如:

    A     B     C    formula    value
-   -     -     -   --------    -----
1.  2     1     3    (A+B)*C      9
2. 100   null   2      A/C       50

感谢和最好的问候

1 个答案:

答案 0 :(得分:1)

这很有意思。我不确定这是最有效的方法,但这是一个有效的解决方案...

CREATE TABLE tmpMaths (ID INT IDENTITY(1,1), A INT, B INT, C INT, formula VARCHAR(255), formulaResult FLOAT);
INSERT tmpMaths (A, B, C, formula) VALUES (2, 1, 3, '(A+B)*C')
, (100, NULL, 2, 'A/C/C/C/A');

DECLARE @Results TABLE (ID INT, Result FLOAT);
DECLARE @SQL2 VARCHAR(MAX) = '';
SELECT @SQL2 += ' UNION ALL SELECT ' + CAST(ID AS VARCHAR(255)) + ' ID, 1.0 * ' 
    + REPLACE(REPLACE(REPLACE(formula, 'A', ISNULL(A, '')), 'B', ISNULL(B, '')), 'C', ISNULL(C, '')) 
    + ' Result FROM tmpMaths WHERE ID = ' + CAST(ID AS VARCHAR(255))
FROM tmpMaths;
SELECT @SQL2 = STUFF(@SQL2, 1, 11, '');
INSERT @Results (ID, Result)
EXEC(@SQL2);

UPDATE M SET formulaResult = R.Result --SELECT M.ID, A, B, C, formula, Result
FROM tmpMaths M
JOIN @Results R ON R.ID = M.ID;

SELECT * FROM tmpMaths;

DROP TABLE tmpMaths;

如果您不知道所有列名称,那么类似下面的内容会更复杂,但无论如何......(基本上它通过动态SQL获取列名称):

CREATE TABLE tmpMaths (ID INT IDENTITY(1,1), A INT, B INT, C INT, formula VARCHAR(255));
INSERT tmpMaths (A, B, C, formula) VALUES (2, 1, 3, '(A+B)*C')
, (100, NULL, 2, 'A/C/C/C/A');

DECLARE @replacecount INT = (
    SELECT COUNT(*)
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'tmpMaths'
    AND COLUMN_NAME NOT IN ('ID', 'formula')) -- get the count of columns, unnecessary if it's always just 3 (A, B, C)
, @replace VARCHAR(MAX) = ''
, @cols VARCHAR(MAX) = '';

SELECT @replace += ', ''' + COLUMN_NAME + ''', ISNULL(' + COLUMN_NAME + ', ''''))' -- for replacing the column names in the formula
     , @cols += ', ' + COLUMN_NAME -- for selecting the columns in output, unnecessary if it's always just A, B, C
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmpMaths'
AND COLUMN_NAME NOT IN ('ID', 'formula');

DECLARE @selectreplace NVARCHAR(MAX) = REPLICATE('REPLACE(', @replacecount) + 'formula' + @replace; -- e.g. REPLACE(REPLACE(REPLACE(formula, 'A', A), 'B', B), 'C' C)

IF OBJECT_ID('tempdb..#tmpEvaluated') IS NOT NULL DROP TABLE #tmpEvaluated;
CREATE TABLE #tmpEvaluated (ID INT, Evaluated VARCHAR(255));
DECLARE @SQL VARCHAR(MAX) = 'INSERT #tmpEvaluated (ID, Evaluated) SELECT ID, ' + @selectreplace + ' FROM tmpMaths';
EXEC(@SQL); -- produces the formula with numbers instead of column names

IF OBJECT_ID('tempdb..#tmpResults') IS NOT NULL DROP TABLE #tmpResults;
CREATE TABLE #tmpResults (ID INT, Result FLOAT);
DECLARE @SQL2 VARCHAR(MAX) = '';
SELECT @SQL2 += ' UNION ALL SELECT ' + CAST(ID AS VARCHAR(255)) + ' ID, 1.0 * ' + Evaluated + ' Result FROM #tmpEvaluated WHERE ID = ' + CAST(ID AS VARCHAR(255))
FROM #tmpEvaluated;
SELECT @SQL2 = STUFF(@SQL2, 1, 11, '');
INSERT #tmpResults (ID, Result)
EXEC(@SQL2); -- gets the result of the formula with numbers in it (a series of UNION ALL statements)
PRINT @SQL2;

DECLARE @output VARCHAR(MAX) = 'SELECT M.ID' + @cols + ', formula, result FROM tmpMaths M JOIN #tmpResults R ON R.ID = M.ID';
EXEC(@output);

DROP TABLE tmpMaths;