情况:
我经常有(对数据库没有评论,它是历史 :))列,其中值是分开的。
因此,假设我们有一列params
包含例如1,2,3,4,5
.
如果我需要基于值的表,我用一个dbo.fn_Split()
函数将它们拆分(可以在网上找到几个版本 - 但超出了这里的范围)。所以我得到了我的虚拟表。
今天我遇到了一个情况,我有一个专栏,里面有这个内容110&mode=tree
。
因为我需要ID
我对自己说的唯一...像往常一样,拆分并仅获取第一个值:
SELECT TOP 1 [value] FROM dbo._fnSplit('110&mode=tree','&')
因为我需要 int 的值,所以我在它周围添加了一个 CAST() 。
CAST((SELECT TOP 1 [value] FROM dbo._fnSplit('110&mode=tree','&')) AS int)
现在执行后我得到:
mode=tree 不能转换为 int 类型
哈?我只得到第一个值Id
(我仔细检查了结果),但它仍然尝试转换第二个值。所以似乎 SQL Server 在执行时处理它的方式不同。
问题:
那么通常可以控制执行计划如何处理这种行为吗?
边注:
我现在解决了这个问题:
[...] WHERE id = CAST((CASE WHEN k.param LIKE '%&%' THEN LEFT(k.swindowparam,PATINDEX('%&%',k.param)-1) ELSE k.swindowparam END) AS int))
检查字符串是否包含 &,如果是,则为 LEFT,长度为PATINDEX
.
编辑:
这是拆分功能:
CREATE FUNCTION dbo.fn_Split(@text nvarchar(4000), @delimiter char(1) = ',')
RETURNS @Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value nvarchar(4000)
)
AS
BEGIN
DECLARE @index int
SET @index = -1
SET @text = RTRIM(LTRIM(@text))
WHILE (LEN(@text) > 0)
BEGIN
SET @index = CHARINDEX(@delimiter , @text)
IF (@index = 0) AND (LEN(@text) > 0)
BEGIN
INSERT INTO @Strings VALUES (@text)
BREAK
END
IF (@index > 1)
BEGIN
INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
ELSE
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
RETURN
END