Sql 在文本列中存储数字数据时出现问题-选择…介于
几年前,我在一个系统上工作,其中一个数字主键存储在[SQL Server]varchar列中,因此当使用BEVER运算符进行查询时,我很快就失去了联系:Sql 在文本列中存储数字数据时出现问题-选择…介于,sql,performance,Sql,Performance,几年前,我在一个系统上工作,其中一个数字主键存储在[SQL Server]varchar列中,因此当使用BEVER运算符进行查询时,我很快就失去了联系: SELECT ID FROM MyTable WHERE ID BETWEEN 100 AND 110; 结果: 100 102 103 109 110 11 这简直是个糟糕的设计。然而,我正在开发一个第三方ERP系统,正如你所想象的,它需要通用性和灵活性;因此,我们有各种表格,其中提供了字母数字字段,而业务仅使用数字-因此可能会出现类似的
SELECT ID FROM MyTable WHERE ID BETWEEN 100 AND 110;
结果:
100
102
103
109
110
11
这简直是个糟糕的设计。然而,我正在开发一个第三方ERP系统,正如你所想象的,它需要通用性和灵活性;因此,我们有各种表格,其中提供了字母数字字段,而业务仅使用数字-因此可能会出现类似的问题
我猜这是一个相当普遍的问题;我有一个足够简单的解决方案,但我很好奇其他人是如何处理这些问题的
我的简单解决方案是:
SELECT ID FROM MyTable
WHERE ID BETWEEN iStartValue AND iEndValue
AND (LENGTH(ID) = LENGTH(iStartValue)
OR LENGTH(ID) = LENGTH(iEndValue));
正如您可能知道的,这是一个Oracle系统,但我通常在SQL Server中工作——因此,也许数据库无关解决方案更可取
编辑1:我不明白为什么专有解决方案不受欢迎
编辑2:感谢所有的回复。我不确定我是否对没有一个明显的、复杂的解决方案感到失望,但我相应地感到高兴的是,我似乎没有遗漏任何明显的东西
我想我还是喜欢我自己的解决方案;它很简单而且有效-有什么理由我不应该使用它吗?我不相信它比其他解决方案的效率低多少(如果有的话)
我意识到在一个理想的世界里,这个问题是不存在的;但不幸的是,我并不是在理想的环境中工作,通常情况下,这是一种充分利用不利情况的情况。如果您确定ID中的值仅为数字,为什么不直接将其转换为强制转换
WHERE CAST(ID as int) BETWEEN iStartValue AND iEndValue
编辑1:
强制转换方法的一个扩展应该是使用子查询来提取所有数字记录。请注意-我不认为这个方法比上面建议的方法好,我包括它,因为它回答了问题
SELECT ID
FROM (
SELECT ID
FROM MyTable
WHERE ISNUMERIC(ID) = 1
AND CHARINDEX ('.', ID) = 0
AND CHARINDEX ('-', ID) = 0
) a
WHERE CONVERT(bigint, ID) BETWEEN 0 AND 12000
ORDER BY LENGTH(ID) ASC, ID
实际上并不需要检查“-”和“.”字符。我假设你的身份证不能是负数或小数 换个演员怎么样
SELECT ID FROM MyTable
WHERE cast(ID as signed) BETWEEN cast(iStartValue as signed) AND cast(iEndValue as signed)
给出的这个语法是MySQL,但是T-SQl也有类似的CAST操作符。我不知道这是否适用于您的情况,但是 如何向表中添加一个实际的数字列,并填充该值(SQL Server您可以使用一个计算列,并在其上建立持久化索引) 在其他供应商中,DBs使用一些其他机制来填充(触发器、物化视图等) 然后使用该列而不是varchar列 也许LPAD(id,12,”)适合您。 它应该使所有列值的宽度为12,并在左侧填充空格 我也会有点担心varchar2列中的数字
如果你做任何数字的事情,比如分析,你可能会在非数字数据上得到一个例外。另一个选择是用零填充数字,并在上面使用between操作符。出于可搜索性的原因,最好将其作为第二个where条件(以便仍然可以使用可能的索引)。像这样的
SELECT ID FROM MyTable
WHERE ID BETWEEN iStartValue AND iEndValue
And Right('0000000000' + ID, 10) Between iStartValue and iEndValue
我在SQLServer中对此进行了测试,它返回了正确的值。在第一个示例中,有历史数据阻止了这种情况的发生-数据库被多个应用程序使用,而我们没有能力更改它。在第二种情况下,许多表是通用/多用途的,因此在某些情况下,应用程序的其他部分允许/使用alpha。以这种方式强制转换将防止使用索引。欢迎使用TableScan。[如果不清楚-当表中有字母数字数据时强制转换导致错误(SQL错误:ORA-01722:无效数字)]我已经更新了它,以显示一个应该可以工作的方法。然而,我并不推荐它!回复:David B的观点——在这种情况下,可以使用基于函数的索引。是的,我考虑过这一点,但我的建议并不恰当(请参阅对RB的评论)。这是个好主意,但在这两种情况下,我都不能改变模式。在第二个示例中,我正在为ERP系统构建附加功能,因此我不得不在ERP开发人员设定的范围内工作。很遗憾,您可以添加视图吗?你可以把你的计算列(和聚集索引)放在那里。我已经有一年左右没有使用Oracle了,但是如果你在强制转换时遇到转换错误,那么当它在上面的语句中进行隐式转换时,你不会遇到错误吗?LENGTH是一个用于处理字符串的函数,所以不会。