Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL查询动态中使用公式?_Sql_Sql Server_Database - Fatal编程技术网

如何在SQL查询动态中使用公式?

如何在SQL查询动态中使用公式?,sql,sql-server,database,Sql,Sql Server,Database,我需要您的帮助来动态创建查询, 如何从其他表中的公式填充数据值 下面的示例 Table A ID Amount 1 50 2 40 3 50 Table B ID FormulaID VALUE X 1+2+3 Y 1-2+3 Result Expectation ID FormulaID VALUE X 1+2+3 140 Y 1-2+3 60 谢谢基于@Ashwin Nair

我需要您的帮助来动态创建查询, 如何从其他表中的公式填充数据值

下面的示例

Table A 
ID   Amount 
1    50 
2    40 
3    50 

Table B 
ID   FormulaID   VALUE 
X    1+2+3 
Y    1-2+3 

Result Expectation 
ID   FormulaID   VALUE 
X    1+2+3       140 
Y    1-2+3       60 

谢谢

基于@Ashwin Nair的评论,我对此感到厌倦。它很好用

DECLARE @count INT = 1
DECLARE @Formula VARCHAR(200)
,@FormulaID VARCHAR(100)
,@IDstring VARCHAR(20)
,@operator VARCHAR(1)

CREATE TABLE #temp (RowID INT IDENTITY(1, 1),FormulaID VARCHAR(100),ID INT,SignOper VARCHAR(1),FORMULA VARCHAR(100),Flag INT,VALUE INT)
WHILE ( SELECT COUNT(*)FROM formulaT) >= @count
BEGIN
--Total formula records
SET @Formula = (SELECT formulaID FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID) RowID,*FROM formulaT) a WHERE RowID = @count)
SET @FormulaID = (SELECT ID FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID) RowID,* FROM formulaT) a WHERE RowID = @count)
DECLARE @ID INT
SET @ID = PATINDEX('%[^0-9]%', @Formula)
BEGIN
    WHILE @ID > 0
    BEGIN
        --spliting a formula --ID based on the charactors
        SET @IDstring = SUBSTRING(@Formula, 1, @ID - 1)
        SET @operator = SUBSTRING(@Formula, @ID, 1)
        SET @Formula = REPLACE(@Formula, @IDstring + @operator, '')
        INSERT INTO #temp
        SELECT @FormulaID,CAST(@IDstring AS INT),@operator,(SELECT CAST(Amount AS VARCHAR)  FROM amtt
                WHERE Id = CAST(@IDstring AS INT)),0,0
        SET @ID = PATINDEX('%[^0-9]%', @Formula)
        SET @IDstring = NULL
    END
    INSERT INTO #temp
    SELECT @FormulaID
        ,@Formula
        ,''
        ,(SELECT CAST(Amount AS VARCHAR)
            FROM amtt
            WHERE Id = CAST(@Formula AS INT))
        ,0,0
        --spliting a formula --ID based on the charactors
END
DECLARE @RowNo INT = (SELECT MIN(RowID) FROM #temp  WHERE FormulaID = @FormulaID)
SET @formula = ''
WHILE (SELECT MAX(RowID)FROM #temp WHERE FormulaID = @FormulaID) >= @RowNo
BEGIN
    SET @formula = @formula + (SELECT ISNULL(FORMULA + SignOper, SignOper)  FROM #temp  WHERE FormulaID = @FormulaID AND RowID = @RowNo)
    SET @RowNo = @RowNo + 1
END
INSERT INTO #temp
SELECT @FormulaID
    ,0,'',@formula,1,0
DECLARE @QUERY VARCHAR(250) = (SELECT 'sp_executesql N' + '''select ' + @formula + '''')
CREATE TABLE #CALC (VAL INT)
PRINT @QUERY
INSERT INTO #CALC
EXEC (@QUERY)
INSERT INTO #temp
SELECT @FormulaID
    ,0,'',@formula,2,(SELECT val FROM #CALC ) 
DROP TABLE #CALC
SET @Count = @count + 1
END

SELECT F.ID
,F.FORMULAID
,FORMULA
,VALUE
FROM formulaT F
INNER JOIN #temp T ON T.FORMULAID = F.ID
AND T.FLAG = 2

DROP TABLE #temp
--Output
--ID  FORMULAID  FORMULA      VALUE
--X   1+2+3      50+40+50     140
--Y   1-2+3      50-40+50     60
--Please let me know this answer is helpful or not..
谢谢
Karthik

基于@Ashwin Nair的评论,我对此感到厌倦。它很好用

DECLARE @count INT = 1
DECLARE @Formula VARCHAR(200)
,@FormulaID VARCHAR(100)
,@IDstring VARCHAR(20)
,@operator VARCHAR(1)

CREATE TABLE #temp (RowID INT IDENTITY(1, 1),FormulaID VARCHAR(100),ID INT,SignOper VARCHAR(1),FORMULA VARCHAR(100),Flag INT,VALUE INT)
WHILE ( SELECT COUNT(*)FROM formulaT) >= @count
BEGIN
--Total formula records
SET @Formula = (SELECT formulaID FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID) RowID,*FROM formulaT) a WHERE RowID = @count)
SET @FormulaID = (SELECT ID FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID) RowID,* FROM formulaT) a WHERE RowID = @count)
DECLARE @ID INT
SET @ID = PATINDEX('%[^0-9]%', @Formula)
BEGIN
    WHILE @ID > 0
    BEGIN
        --spliting a formula --ID based on the charactors
        SET @IDstring = SUBSTRING(@Formula, 1, @ID - 1)
        SET @operator = SUBSTRING(@Formula, @ID, 1)
        SET @Formula = REPLACE(@Formula, @IDstring + @operator, '')
        INSERT INTO #temp
        SELECT @FormulaID,CAST(@IDstring AS INT),@operator,(SELECT CAST(Amount AS VARCHAR)  FROM amtt
                WHERE Id = CAST(@IDstring AS INT)),0,0
        SET @ID = PATINDEX('%[^0-9]%', @Formula)
        SET @IDstring = NULL
    END
    INSERT INTO #temp
    SELECT @FormulaID
        ,@Formula
        ,''
        ,(SELECT CAST(Amount AS VARCHAR)
            FROM amtt
            WHERE Id = CAST(@Formula AS INT))
        ,0,0
        --spliting a formula --ID based on the charactors
END
DECLARE @RowNo INT = (SELECT MIN(RowID) FROM #temp  WHERE FormulaID = @FormulaID)
SET @formula = ''
WHILE (SELECT MAX(RowID)FROM #temp WHERE FormulaID = @FormulaID) >= @RowNo
BEGIN
    SET @formula = @formula + (SELECT ISNULL(FORMULA + SignOper, SignOper)  FROM #temp  WHERE FormulaID = @FormulaID AND RowID = @RowNo)
    SET @RowNo = @RowNo + 1
END
INSERT INTO #temp
SELECT @FormulaID
    ,0,'',@formula,1,0
DECLARE @QUERY VARCHAR(250) = (SELECT 'sp_executesql N' + '''select ' + @formula + '''')
CREATE TABLE #CALC (VAL INT)
PRINT @QUERY
INSERT INTO #CALC
EXEC (@QUERY)
INSERT INTO #temp
SELECT @FormulaID
    ,0,'',@formula,2,(SELECT val FROM #CALC ) 
DROP TABLE #CALC
SET @Count = @count + 1
END

SELECT F.ID
,F.FORMULAID
,FORMULA
,VALUE
FROM formulaT F
INNER JOIN #temp T ON T.FORMULAID = F.ID
AND T.FLAG = 2

DROP TABLE #temp
--Output
--ID  FORMULAID  FORMULA      VALUE
--X   1+2+3      50+40+50     140
--Y   1-2+3      50-40+50     60
--Please let me know this answer is helpful or not..
谢谢
Karthik

我认为,你的数据库设计是错误的。你的实际需求是什么?你可以考虑上面的数据库设计。你应该多加一点背景知识,你会在这个社区得到非常专业的解决方案

我尝试了一些东西,只是用其他样本数据进行测试并给出反馈

DECLARE @TableB table(ID VARCHAR(50),FormulaID VARCHAR(50) ,VALUE INT)
INSERT INTO @TableB VALUES('X','1+2+3',NULL),('Y','1-2+3',NULL)

DECLARE @TableA table (ID INT,Amount INT)
INSERT INTO @TableA values(1,50 ),(2,40 ),(3,50 )

declare @input varchar(50)='a+b-c*d'
declare @delimiter varchar(50)='-+/*'


;WITH CTE
AS (
    SELECT id
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN substring(FormulaID, 0, PATINDEX('%[' + @delimiter + ']%', FormulaID))
            END numbers
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN substring(FormulaID, PATINDEX('%[' + @delimiter + ']%', FormulaID), 1)
            END delimeter
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN stuff(FormulaID, 1, PATINDEX('%[' + @delimiter + ']%', FormulaID), '')
            END input
        ,1 RN
        ,FormulaID
    FROM @TableB

    UNION ALL

    SELECT id
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN cast(substring(input, 0, PATINDEX('%[' + @delimiter + ']%', input)) AS VARCHAR(50))
            ELSE cast(input AS VARCHAR(50))
            END
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN substring(input, PATINDEX('%[' + @delimiter + ']%', input), 1)
            END
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN stuff(input, 1, PATINDEX('%[' + @delimiter + ']%', input), '')
            END
        ,RN + 1
        ,FormulaID
    FROM cte
    WHERE len(input) > 0
    )
    ,CTE1
AS (
    SELECT c.id
        ,c.numbers
        ,a.amount
        ,c.delimeter
        ,rn
        ,FormulaID
    FROM CTE C
    INNER JOIN @tableA a ON c.numbers = a.id
    )
    ,CTE4
AS (
    SELECT id
        ,formulaid
        ,amount
        ,delimeter
        ,numbers
        ,rn
    FROM cte1
    WHERE rn = 1

    UNION ALL

    SELECT a.id
        ,b.formulaid
        ,CASE 
            WHEN b.delimeter = '+'
                THEN b.amount + a.amount
            WHEN b.delimeter = '-'
                THEN b.amount - a.amount
            WHEN b.delimeter = '*'
                THEN b.amount * a.amount
            END
        ,a.delimeter
        ,a.numbers
        ,a.RN
    FROM cte1 a
    INNER JOIN cte4 b ON a.id = b.id
    WHERE a.rn = b.rn + 1
    )
SELECT id
    ,formulaid
    ,amount
FROM cte4
WHERE delimeter IS NULL 

我认为,你的数据库设计是错误的。你的实际需求是什么?你认为上面的数据库设计是什么样的。你应该多加一点背景知识,你会在这个社区得到非常专业的解决方案

我尝试了一些东西,只是用其他样本数据进行测试并给出反馈

DECLARE @TableB table(ID VARCHAR(50),FormulaID VARCHAR(50) ,VALUE INT)
INSERT INTO @TableB VALUES('X','1+2+3',NULL),('Y','1-2+3',NULL)

DECLARE @TableA table (ID INT,Amount INT)
INSERT INTO @TableA values(1,50 ),(2,40 ),(3,50 )

declare @input varchar(50)='a+b-c*d'
declare @delimiter varchar(50)='-+/*'


;WITH CTE
AS (
    SELECT id
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN substring(FormulaID, 0, PATINDEX('%[' + @delimiter + ']%', FormulaID))
            END numbers
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN substring(FormulaID, PATINDEX('%[' + @delimiter + ']%', FormulaID), 1)
            END delimeter
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', FormulaID) > 0
                THEN stuff(FormulaID, 1, PATINDEX('%[' + @delimiter + ']%', FormulaID), '')
            END input
        ,1 RN
        ,FormulaID
    FROM @TableB

    UNION ALL

    SELECT id
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN cast(substring(input, 0, PATINDEX('%[' + @delimiter + ']%', input)) AS VARCHAR(50))
            ELSE cast(input AS VARCHAR(50))
            END
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN substring(input, PATINDEX('%[' + @delimiter + ']%', input), 1)
            END
        ,CASE 
            WHEN PATINDEX('%[' + @delimiter + ']%', input) > 0
                THEN stuff(input, 1, PATINDEX('%[' + @delimiter + ']%', input), '')
            END
        ,RN + 1
        ,FormulaID
    FROM cte
    WHERE len(input) > 0
    )
    ,CTE1
AS (
    SELECT c.id
        ,c.numbers
        ,a.amount
        ,c.delimeter
        ,rn
        ,FormulaID
    FROM CTE C
    INNER JOIN @tableA a ON c.numbers = a.id
    )
    ,CTE4
AS (
    SELECT id
        ,formulaid
        ,amount
        ,delimeter
        ,numbers
        ,rn
    FROM cte1
    WHERE rn = 1

    UNION ALL

    SELECT a.id
        ,b.formulaid
        ,CASE 
            WHEN b.delimeter = '+'
                THEN b.amount + a.amount
            WHEN b.delimeter = '-'
                THEN b.amount - a.amount
            WHEN b.delimeter = '*'
                THEN b.amount * a.amount
            END
        ,a.delimeter
        ,a.numbers
        ,a.RN
    FROM cte1 a
    INNER JOIN cte4 b ON a.id = b.id
    WHERE a.rn = b.rn + 1
    )
SELECT id
    ,formulaid
    ,amount
FROM cte4
WHERE delimeter IS NULL 

您使用的前端是什么,因为前端可能更简单?
表A中的记录数是固定的还是至少少于10?操作的数量是否限于+和-?使用存储过程是您的选择吗?嗨,奈,谢谢您的回答。是的,在前端可能会更容易,但我将在存储过程中处理它:)。表A中的记录数不是固定的,可以超过10条,而且操作不仅是+和-,还可以是这样的(1*2)-(3+1)。似乎没有直接的方法可以做到这一点,但既然您对SP没有问题,请分解问题:……首先
从[表B]中选择FormulaId
然后循环浏览记录,并使用
子字符串
(+,-,*,/,(,)搜索到一个
数组
,将数字取出。对于数组的每个元素,从[Table A]中选择Amount,其中Id=…
。一旦你得到了一个包含实际值的字符串,使用
exec
基本上运行公式。一旦你得到了替换的字符串,你可以使用
sp_executesql N'select 50+40+50'
(例如)运行公式。我不知道,为什么这个问题被否决了?你使用的前端是什么,因为它在前端可能更容易?
表A中的记录数是固定的还是至少少于10?操作的数量是否限于+和-?使用存储过程是您的选择吗?嗨,奈,谢谢您的回答。是的,在前端可能会更容易,但我将在存储过程中处理它:)。表A中的记录数不是固定的,可以超过10条,而且操作不仅是+和-,还可以是这样的(1*2)-(3+1)。似乎没有直接的方法可以做到这一点,但既然您对SP没有问题,请分解问题:……首先
从[表B]中选择FormulaId
然后循环浏览记录,并使用
子字符串
(+,-,*,/,(,)搜索到一个
数组
,将数字取出。对于数组的每个元素,从[Table A]中选择Amount,其中Id=…
。一旦你得到了一个包含实际值的字符串,使用
exec
基本上运行公式。一旦你得到了替换的字符串,你可以使用
sp\u executesql N'select 50+40+50'
(例如)运行公式。我不知道,为什么这个问题会被向上投票?