这个简单的SQL更新是一个等待发生的错误吗?如何重写它?
我需要检查表1中的科目数值。如果ACCT_NUM的前缀是“GF0”,那么我需要忽略“GF0”前缀,并获取剩余字符串中最右边的7个字符。如果在account_x_master或CW_CLIENT_STAGE中找不到此结果值,则该记录将被标记为错误 下面的内容似乎很有用,但我有一个顾虑这个简单的SQL更新是一个等待发生的错误吗?如何重写它?,sql,sql-server,Sql,Sql Server,我需要检查表1中的科目数值。如果ACCT_NUM的前缀是“GF0”,那么我需要忽略“GF0”前缀,并获取剩余字符串中最右边的7个字符。如果在account_x_master或CW_CLIENT_STAGE中找不到此结果值,则该记录将被标记为错误 下面的内容似乎很有用,但我有一个顾虑 UPDATE table_1 SET Error_Ind = 'GW001' WHERE LEFT(ACCT_NUM, 3) = 'GF0' AND RIGHT(SUBSTRING(A
UPDATE
table_1
SET
Error_Ind = 'GW001'
WHERE
LEFT(ACCT_NUM, 3) = 'GF0'
AND RIGHT(SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3), 7) NOT IN
(
SELECT
acct_num
FROM
account_x_master
)
AND RIGHT(SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3), 7) NOT IN
(
SELECT
CW_CLIENT_STAGE.AGS_NUM
FROM
dbo.CW_CLIENT_STAGE
)
我担心的是SQL Server可能会尝试执行子字符串操作
SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3)
这将导致计算的负值并导致SQL失败。当然,这不会失败,因为子字符串操作只应用于那些我们至少有3个字符长的记录,如果
LEFT(ACCT_NUM, 3) = 'GF0'
我们先申请。如果可能,我希望避免向表中添加新列。简化和减少开销的奖励积分:-)
如何重写此更新SQL以防止出现这种情况?您有一个非常值得关注的问题,因为SQL Server将重新排列
WHERE
中表达式的求值顺序
保证SQL语句中操作顺序的唯一方法是使用case
。我认为没有办法捕获对substring()
的失败调用。没有类似于try\u convert()
的try\u substring()
因此:
这更难看。而且,可能有办法解决这个问题,比如使用通配符而不是字符串操作的LIKE
。但是,案例
将保证子字符串()
只在足够长的字符串上运行,因此不会生成错误。您有一个非常合理的担忧,因为SQL Server将重新排列WHERE
中表达式的求值顺序
保证SQL语句中操作顺序的唯一方法是使用case
。我认为没有办法捕获对substring()
的失败调用。没有类似于try\u convert()
的try\u substring()
因此:
这更难看。而且,可能有办法解决这个问题,比如使用通配符而不是字符串操作的LIKE
。但是,案例将保证子字符串()
只在足够长的字符串上运行,因此不会生成错误。请尝试以下查询。
由于SQLWHERE
子句中不存在短路和或
,所以实现的唯一方法是通过CASE
语法
我注意到您在的不同部分有两个不在
比较中,其中
合并为一个。
请注意,CASE
条件是=3
,而不是>3
,因为允许右(“”,x)
。
还要注意将CASE
与不在一起时的正确用法
UPDATE table_1
SET
Error_Ind = 'GW001'
select * from table_1
WHERE
LEFT(ACCT_NUM, 3) = 'GF0'
AND CASE
WHEN LEN(ACCT_NUM)>=3
THEN RIGHT(SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3), 7)
ELSE NULL END NOT IN
(
SELECT acct_num as num
FROM account_x_master
UNION
SELECT CW_CLIENT_STAGE.AGS_NUM as num
FROM dbo.CW_CLIENT_STAGE
)
请尝试下面的查询。
由于SQLWHERE
子句中不存在短路和或
,所以实现的唯一方法是通过CASE
语法
我注意到您在的不同部分有两个不在
比较中,其中
合并为一个。
请注意,CASE
条件是=3
,而不是>3
,因为允许右(“”,x)
。
还要注意将CASE
与不在一起时的正确用法
UPDATE table_1
SET
Error_Ind = 'GW001'
select * from table_1
WHERE
LEFT(ACCT_NUM, 3) = 'GF0'
AND CASE
WHEN LEN(ACCT_NUM)>=3
THEN RIGHT(SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3), 7)
ELSE NULL END NOT IN
(
SELECT acct_num as num
FROM account_x_master
UNION
SELECT CW_CLIENT_STAGE.AGS_NUM as num
FROM dbo.CW_CLIENT_STAGE
)
正如其他人所说,你的担心是正确的
我将对你的查询做两个更改
1) 为了避免子字符串
参数中出现负值,我们可以使用STUFF
重写它:
SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3)
相当于:
STUFF(ACCT_NUM, 1, 3, '')
我们用空字符串替换前三个字符,而不是提取字符串的尾部。如果字符串短于3个字符,则结果为空字符串
顺便说一下,如果您的ACCT_NUM
可能以空格结尾,它们将被子字符串
版本修剪,因为LEN
不计算尾随空格
2) 而不是
LEFT(ACCT_NUM, 3) = 'GF0'
使用:
如果在ACCT\u NUM
上有索引,并且只有相对较少的行以GF0
开头,则将使用索引。如果使用函数,例如LEFT
,则无法使用索引
因此,最终查询变成:
UPDATE
table_1
SET
Error_Ind = 'GW001'
WHERE
ACCT_NUM LIKE 'GF0%'
AND RIGHT(STUFF(ACCT_NUM, 1, 3, ''), 7) NOT IN
(
SELECT
acct_num
FROM
account_x_master
)
AND RIGHT(STUFF(ACCT_NUM, 1, 3, ''), 7) NOT IN
(
SELECT
CW_CLIENT_STAGE.AGS_NUM
FROM
dbo.CW_CLIENT_STAGE
)
正如其他人所说,你的担心是正确的
我将对你的查询做两个更改
1) 为了避免子字符串
参数中出现负值,我们可以使用STUFF
重写它:
SUBSTRING(ACCT_NUM, 4, LEN(ACCT_NUM) - 3)
相当于:
STUFF(ACCT_NUM, 1, 3, '')
我们用空字符串替换前三个字符,而不是提取字符串的尾部。如果字符串短于3个字符,则结果为空字符串
顺便说一下,如果您的ACCT_NUM
可能以空格结尾,它们将被子字符串
版本修剪,因为LEN
不计算尾随空格
2) 而不是
LEFT(ACCT_NUM, 3) = 'GF0'
使用:
如果在ACCT\u NUM
上有索引,并且只有相对较少的行以GF0
开头,则将使用索引。如果使用函数,例如LEFT
,则无法使用索引
因此,最终查询变成:
UPDATE
table_1
SET
Error_Ind = 'GW001'
WHERE
ACCT_NUM LIKE 'GF0%'
AND RIGHT(STUFF(ACCT_NUM, 1, 3, ''), 7) NOT IN
(
SELECT
acct_num
FROM
account_x_master
)
AND RIGHT(STUFF(ACCT_NUM, 1, 3, ''), 7) NOT IN
(
SELECT
CW_CLIENT_STAGE.AGS_NUM
FROM
dbo.CW_CLIENT_STAGE
)
比那更糟;在2012年之前的SQL版本中(甚至可能在更高版本中),即使是CASE
在所有情况下都可能无法确定地短路:在这种情况下,使用STUFF
而不是SUBSTRING
,可以完全避免问题,正如我在回答中所解释的那样;在2012年之前的SQL版本中(甚至可能在更高的版本中),即使是CASE
也不能在所有情况下都确定地短路:在这种情况下,可以使用STUFF
而不是子字符串来完全避免问题,正如我在回答中解释的那样。