几年前,我在一个数字主键存储在[SQL Server] varchar列中的系统上工作,所以当使用BETWEEN运算符查询时,我很快就解开了:
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:感谢所有回复。我不确定我是否感到失望,没有一个明显的,复杂的解决方案,但我相应很高兴看起来我没有错过任何明显的东西!
我想我仍然更喜欢自己的解决方案;它很简单而且有效 - 我有什么理由不使用它吗?我无法相信其他解决方案提供的效率会有多大,甚至更低。
我意识到在理想世界中,这个问题不会存在;但不幸的是,我不是在一个理想的世界中工作,而且往往是一个充分利用糟糕情况的案例。
答案 0 :(得分:7)
如果你确定ID中的值只是数字,为什么不只是CAST呢
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
检查“ - ”和“。”字符并不是真正需要的。我假设你的ID不能是负数或小数。
答案 1 :(得分:2)
我不知道这是否适用于你的情况,但是......
如何将实际数字列添加到表中,并使用值填充(SQL Server可以使用计算列,并在其上建立持久化索引)
在其他供应商中,DB使用其他一些机制来填充(触发器,物化视图等)
然后使用该列而不是varchar ...
答案 2 :(得分:1)
相反如何投射。
SELECT ID FROM MyTable
WHERE cast(ID as signed) BETWEEN cast(iStartValue as signed) AND cast(iEndValue as signed)
给出的语法是MySQL,但T-SQl有类似的CAST运算符。
答案 3 :(得分:1)
也许 LPAD(id,12,'')会对你有用。 它应该使所有列值都宽12,并在左侧填充空格。
另外,我会对varchar2列中的数字有点关注。
如果你做任何数字化的事情,比如分析,你可能会得到非数字数据的例外。
答案 4 :(得分:1)
另一种选择是用零填充你的数字并使用之间的运算符。出于可争夺性原因,最好将其作为第二个条件包含在内(以便仍然可以使用可能的索引)。像这样......
SELECT ID FROM MyTable
WHERE ID BETWEEN iStartValue AND iEndValue
And Right('0000000000' + ID, 10) Between iStartValue and iEndValue
我在SQL Server中对此进行了测试,并返回了正确的值。您可能需要修改它以使用Oracle。
答案 5 :(得分:0)
最后我坚持使用自己的解决方案(参见OP)。非常感谢您的努力。