筛选出的字符串仍会导致SQL语句出错
我正在使用SQLServer2008R2 我正在编写一个零件号生成器应用程序。我们的零件号由9位数字组成,如914602001。在创建新编号之前,如果已经存在,则需要检查多个来源。为了节省时间,我创建了一个简单的源代码联合。工会成员如下:筛选出的字符串仍会导致SQL语句出错,sql,sql-server-2008-r2,Sql,Sql Server 2008 R2,我正在使用SQLServer2008R2 我正在编写一个零件号生成器应用程序。我们的零件号由9位数字组成,如914602001。在创建新编号之前,如果已经存在,则需要检查多个来源。为了节省时间,我创建了一个简单的源代码联合。工会成员如下: SELECT DISTINCT ItemNumber FROM dbo.EngPartNumbers WHERE (ItemNumber NOT LIKE '%[^0-9]%') UNION SELECT DISTINCT ValueText COLLATE
SELECT DISTINCT ItemNumber
FROM dbo.EngPartNumbers
WHERE (ItemNumber NOT LIKE '%[^0-9]%')
UNION
SELECT DISTINCT ValueText COLLATE SQL_Latin1_General_CP1_CI_AS AS ItemNumber
FROM [PDMWE-Bel-ArtProductsDocManagement].dbo.VariableValue AS vv
WHERE (ValueText NOT LIKE '%[^0-9]%') AND (LEN(ValueText) = 9)
第一个表EngPartNumbers是导入到SQL中的Excel文件。它包含一列ItemNumber,并且是varchar数据类型。它必须是varchar,因为我们在命名约定中使用了字母
第二个表是我们的EPDM,其中VariableValue是存储所有变量值的表,它位于variables表中。ValueText列是保存所有变量值的varchar。在我的例子中,我只关心9位数字值,所以我应用了最后一行:
WHERE (ValueText NOT LIKE '%[^0-9]%') AND (LEN(ValueText) = 9)
工会的结果是我所期望的;仅限数字:
这就是我的问题所在。因为我想得到下一个可用的数字,所以我想使用int数据类型,而不是varchar。当我从视图中选择所有内容时,将列强制转换为int,并添加WHERE子句,如下所示:
SELECT ItemNumber
FROM (
SELECT CAST(ItemNumber AS int) AS ItemNumber
FROM vw_PDM_Union_Items
) AS x
WHERE ItemNumber < 800900000
SELECT CAST(ItemNumber AS int) AS ItemNumber
FROM (SELECT DISTINCT ItemNumber
FROM dbo.EngPartNumbers
WHERE (ItemNumber NOT LIKE '%[^0-9]%')
UNION
SELECT DISTINCT ValueText
COLLATE SQL_Latin1_General_CP1_CI_AS AS ItemNumber
FROM [PDMWE-Bel-ArtProductsDocManagement].dbo.VariableValue AS vv
WHERE (ValueText NOT LIKE '%[^0-9]%')
AND (LEN(ValueText) = 9)) AS item
WHERE (ItemNumber NOT LIKE '%[^0-9]%')
但我还是犯了同样的错误。SQL为什么会这样做?背景中发生了什么导致它查看原始表?如果有人能说明这种情况,并给我一个更好的方法来完成这一点,将不胜感激。为了便于操作,我希望使用int列,而不是varchar
提前感谢。使用bigint或decimal:
我还注意到子查询中有一个长度限制。由于SQL Server的工作方式,在尝试转换值后可能会调用此函数
您可以使用case强制执行求值顺序:
我可能建议您实际将此逻辑移到视图中。现在已复制了它
select *
from (
SELECT CAST(valuetext AS int) AS ItemNumber
FROM (
select valuetext='SW-Revision'
union
select '123456789'
) AS vv
WHERE (ValueText NOT LIKE '%[^0-9]%')
) wrapper
where ItemNumber > 0;
我猜这是由于谓词推送。作为解决办法
SELECT *
FROM (
SELECT CAST(CASE WHEN valuetext NOT LIKE '%[^0-9]%' THEN valuetext END AS int) AS ItemNumber
FROM (
select valuetext='SW-Revision'
union
select '123456789'
) AS vv
WHERE (ValueText NOT LIKE '%[^0-9]%')
) wrapper
WHERE ItemNumber > 0
您可以很容易地重新创建此错误
SELECT *
FROM ( SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%'
) t
WHERE ValueText < 10;
给出了以下执行计划:
您可以看到,SQL Server有效地简化了查询,直至:
SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE TRY_CONVERT(INT, ValueText) < 10;
AND t.ValueText NOT LIKE '%[^0-9]%';
这是一种黑客行为,虽然在大多数情况下我不得不使用它,但不能保证它能正常工作,但是使用TOP和一个比您需要的大得多的数字通常会强制中间实现结果
三,。使用大小写表达式删除记录
同样,这是可行的,但我看不出它能保证有效,未来的更新没有理由不承认where谓词和case谓词是相同的,并优化case表达式。我很好奇这是否有效
SELECT ItemNumber
FROM (
SELECT case isnumeric(ItemNumber)
when 1 then CAST(ItemNumber AS int)
else -999999999
end
AS ItemNumber
FROM vw_PDM_Union_Items
) AS x
WHERE ItemNumber < 800900000
and ItemNumber>-999999999
我尝试了一些不同的想法,使用了bigint和decimal,包括您的示例,但仍然出现了以下错误:将nvarchar转换为数据类型numeric时出现算术溢出错误。@GunnarHerman。SQL Server在优化查询时会重新排列查询,因此可能会在筛选之前转换为数值。Microsoft认为这是一项功能,因为它支持某些优化。查看我的答案上的编辑。基本上你在那里创建的是我的视图,它只返回数字并过滤掉字符串,这很好。如果将其包装在select语句中并添加“WHERE ItemNumber<99999999”,则会出现错误。这就是我面临的问题。如果您案例中的view或嵌套SQL语句过滤掉了所有字母数字行,为什么会出现错误?我可以使用方法1并向其中添加一些行以获得所需的内容。这将非常有效,我感谢你详细解释一切。其他人,我感谢你们的回复和帮助我解决这个问题的努力。非常感谢。
SELECT *
FROM ( SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%'
) t
WHERE ValueText < 10;
SELECT *
FROM ( SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%'
) t
WHERE TRY_CONVERT(INT, ValueText) < 10;
SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE TRY_CONVERT(INT, ValueText) < 10;
AND t.ValueText NOT LIKE '%[^0-9]%';
SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE ValueText < 10;
AND t.ValueText NOT LIKE '%[^0-9]%';
DECLARE @T TABLE (ValueText INT)
INSERT @T (ValueText)
SELECT ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%';
SELECT *
FROM @T
WHERE ValueText < 10;
SELECT ValueText
FROM ( SELECT TOP 2147483647 ValueText
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%'
) t
WHERE ValueText < 10;
SELECT *
FROM ( SELECT ValueText = CASE WHEN ValueText NOT LIKE '%[^0-9]%' THEN ValueText END
FROM (VALUES ('A'), ('1')) t (ValueText)
WHERE t.ValueText NOT LIKE '%[^0-9]%'
) t
WHERE ValueText < 10;
SELECT ItemNumber
FROM (
SELECT case isnumeric(ItemNumber)
when 1 then CAST(ItemNumber AS int)
else -999999999
end
AS ItemNumber
FROM vw_PDM_Union_Items
) AS x
WHERE ItemNumber < 800900000
and ItemNumber>-999999999