【问题标题】:How do I select the following string so it returns 3? SELECT '1+2'如何选择以下字符串使其返回 3?选择“1+2”
【发布时间】:2017-07-03 15:22:42
【问题描述】:

在表格的“SumStrings”列中,我有诸如“1+2”或“1+2-3”之类的字符串,如下所示:

SumStrings
1+2
1+2-3

换句话说:

DROP TABLE IF EXISTS #theSums;
CREATE TABLE #theSums (SumStrings VARCHAR(25))
INSERT INTO #theSums
    values
        ('1+2'),
        ('1+2-3');

如何从该表中选择这些总和的结果?即如果只有上述两个字符串在表中,那么选择的结果应该是 3 和 0

这个问题String Expression to be evaluated to number主要是针对创建一个函数我想要一个简单的从表中选择的脚本

【问题讨论】:

  • 没有内置函数,你应该自己写
  • 你为什么要存储这些垃圾?
  • 不知道为什么人们不赞成这个问题。可能不是存储数据的最佳方式仍然是一个有趣的问题 imo
  • @TimSchmelter 也许他是在概括问题,希望发现有一个内置的 SQL Server 函数可以公开 SQL Server 的表达式评估接口?

标签: sql sql-server sql-server-2016


【解决方案1】:

这是使用dynamic sql 的一种方式

DECLARE @sql VARCHAR(8000) 

SELECT @sql = Stuff((SELECT 'union all select ' + sumstrings 
                     FROM   #thesums 
                     FOR xml path('')), 1, 9, '') 

PRINT @sql 

EXEC (@sql) 

【讨论】:

  • 如果sumstrings 未清理,则可能存在 sql 注入。
  • @SqlZim - 希望 sumstrings 被清理;)
  • @SqlZim 只是为了好玩:我使用 XML 的隐式计算文字的能力为我的答案添加了一种方法...... :-D
【解决方案2】:

这里不容易……您可以使用动态创建的语句:

Prdp 的回答很好,只是对 SQL 注入的补充

您可以使用 XML 的隐式功能来计算 a - 这就是反向绘制! - 文字值。没有办法绕过动态 SQL,但这将有助于对抗疯狂的值:

试试这个

SELECT CAST('' AS XML).value('1+2','int') AS Result;

这个例子使用CURSOR,但同样可以使用@Prdp 的方法:

CREATE TABLE YourTable(ComputeString VARCHAR(100));
INSERT INTO YourTable VALUES('1+2'),('-2+3'),('3*(4+5)'),('12/4');

DECLARE @cs VARCHAR(100);

DECLARE c CURSOR FOR SELECT 'SELECT CAST('''' AS XML).value(''' +  REPLACE(ComputeString,'/',' div ') + ''',''int'') AS Result;' FROM YourTable
OPEN c;
FETCH NEXT FROM c INTO @cs;
WHILE @@FETCH_STATUS=0
BEGIN
    PRINT @cs
    EXEC(@cs);
    FETCH NEXT FROM c INTO @cs;
END
CLOSE c;
DEALLOCATE c;
GO
DROP TABLE YourTable;

备注

您必须将 / 作为除数运算符替换为单词 div

【讨论】:

  • 先生,您拥有令人印象深刻的 XML 技能。我看到您编写了不错的 xml 答案 +1
【解决方案3】:

您必须查询字符串并在执行查询的程序中评估它们。这很重要,但是有很多用 flex+bison(或其他工具)编写的语言示例,如果您真的必须存储表达式而不是它们的值,它们将帮助您评估表达式。

【讨论】:

  • @whytheq 即使这意味着编写更难编写和维护的代码?
  • 这只是为了好玩
  • 很抱歉跑题了,但既然你说这是为了好玩,你的评论让我想起了德莱登在他的办公室里对劳伦斯说的话,当时他正要踏上寻找费萨尔的远征。跨度>
  • (升级答案:主要针对最后一条评论!)
【解决方案4】:

另一个动态sql

DECLARE @sql VARCHAR(8000) = ''

SELECT @sql = CONCAT( @sql , ' union all select ',  ts.SumStrings)
FROM #theSums ts 

SELECT @sql = STUFF(@sql, 1,10,'')

PRINT @sql 

EXEC (@sql)

【讨论】:

  • 这在逻辑上与 Pr​​dp 的答案相同,并且它使用了 古怪的更新,需要避免的事情......
  • @Shnugo 我从 2014 年开始我的职业生涯,从那时起我看到人们过去常说古怪的更新方法可能会失败,或者它将在未来的版本中工作。 2013年两个版本的sql server发布后,一直都像老大一样工作
【解决方案5】:

使用replace()+-之前添加分隔符;拆分字符串,然后sum():


在 SQL Server 2016+ 中,您可以使用 string_split()

select 
    t.SumStrings
  , Summed = sum(convert(int,s.value))
from #theSums t
cross apply string_split(replace(replace(SumStrings,'+','|+'),'-','|-'),'|') s
group by t.SumStrings

返回:

+------------+--------+
| SumStrings | Summed |
+------------+--------+
| 1+2        |      3 |
| 1+2-3      |      0 |
+------------+--------+

dbfiddle.uk 演示:http://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=abd084c8fe3758c29c26e29a1f9dfa36


在 2016 年之前的 SQL Server 中,使用 Jeff Moden 的 CSV Splitter 表值函数:

select 
    t.SumStrings
  , Summed = sum(convert(int,s.Item))
from #theSums t
cross apply delimitedsplit8K(replace(replace(SumStrings,'+','|+'),'-','|-'),'|') s
group by t.SumStrings

rextester 演示:http://rextester.com/GTGT29482

返回:

+------------+--------+
| SumStrings | Summed |
+------------+--------+
| 1+2        |      3 |
| 1+2-3      |      0 |
+------------+--------+

拆分字符串的方法有很多种,这个基本前提适用于任何一种。

拆分字符串参考:

【讨论】:

  • 这对运营商来说非常有限
【解决方案6】:

使用临时表。从 sumString 中提取字符串公式并使用 select 执行它,然后将所需的值插入到临时表中。逐行执行此操作。

设置表格: 创建表 sumString( 公式 varchar(20) )

CREATE TABLE temp(
    result varchar(20)
)

INSERT INTO sumString(formula)
VALUES 
('1+3'),
('1+2-3')

解决办法:

DECLARE @expression varchar(20)

WHILE(EXISTS(SELECT 1 FROM sumString))

BEGIN
    SELECT TOP(1) @expression = formula 
    FROM sumString
    INSERT INTO temp
    --the key is to execute with select as a string so the string formula will be evaluate
    exec ('select '+ @exp)  
    DELETE TOP (1) FROM sumString
END

结果:

--check the result--

SELECT * FROM temp

result
4
0

【讨论】:

    猜你喜欢
    • 2015-07-01
    • 1970-01-01
    • 2019-05-09
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多