选择转换为小数的最大 varchar
Posted
技术标签:
【中文标题】选择转换为小数的最大 varchar【英文标题】:Selecting maximum varchar casted into a decimal 【发布时间】:2016-05-10 20:49:43 【问题描述】:我正在尝试从列中获取最大 Decimal 值,然后将 1 添加到它以获得下一个值。但是,该列的值是 varchar 类型,这意味着我必须过滤以确保它只尝试转换它可以转换的值,例如“123”,同时避免使用像“123a”这样的值
到目前为止我尝试的是这样的:
SELECT
(CAST(MAX(Id) AS DECIMAL(38,0)) + 1) AS 'New ID'
FROM database
WHERE Id NOT LIKE '%[^0-9]%' --filters out non-numeric ID values
AND (LEN(Id) + 1) < 39 --ensures ID is less than length 39
但是,当我运行这个时,如果 ID 列中存在 9 和 100 等值,则 MAX 会优先考虑 9 而不是 100。
我也尝试过:
SELECT
(CAST(MAX(CAST(Id AS DECIMAL(38,0))) AS DECIMAL(38,0)) + 1) AS 'New ID'
FROM database
WHERE Id NOT LIKE '%[^0-9]%'
AND (LEN(Id) + 1) < 39
但是,这会导致将 varchar 转换为数字时出错,因为我假设它会在过滤 WHERE 子句中的非数字 ID 之前尝试将其转换为小数。我也试过在开始时去掉多余的演员,但这仍然有同样的问题。
感谢您的帮助!
【问题讨论】:
切换顺序,使转换发生在最大值之前。MAX(CAST(Id AS DECIMAL(38,0)) + 1) AS 'New ID'
或类似的东西.. 或使用 CTE 首先消除非数字 ID,然后强制转换以获得最大 + 1
【参考方案1】:
您缺少的是空字符串。您的条件:当 Id 为空字符串时,Id NOT LIKE '%[^0-9]%' 为真。这应该有效:
SELECT
(MAX(CAST(Id AS DECIMAL(38,0))) + 1) AS 'New ID'
FROM database
WHERE Id NOT LIKE '%[^0-9]%'
AND Id <> ''
AND (LEN(Id) + 1) < 39
外部 CAST 是多余的(MAX 将返回与其参数相同的类型)。
PS:WHERE 子句在 SELECT 子句之前进行求值,所以如果过滤掉 WHERE 中的无效值,SELECT 中的转换不会失败。
【讨论】:
【参考方案2】:你应该使用try_convert()
:
SELECT MAX(TRY_CONVERT(DECIMAL(38, 0), id)) + 1 AS [New ID]
FROM database
WHERE Id NOT LIKE '%[^0-9]%' AND (LEN(Id) + 1) < 39 ;
您的示例转换回小数,但我认为您需要一个字符串:
SELECT TRY_CONVERT(VARCHAR(38), MAX(TRY_CONVERT(DECIMAL(38, 0), id)) + 1) AS [New ID]
FROM database
WHERE Id NOT LIKE '%[^0-9]%' AND (LEN(Id) + 1) < 39 ;
您面临的问题是基于 SQL Server 处理查询的方式。我们打算在SELECT
之前处理WHERE
子句。但是,这可能不是计算的设置方式。因此,SQL Server 最终会在转换将被过滤掉的值方面做不必要的工作——但随后会发生错误并中断查询。
在我看来,这是 SQL Server 实现中的一个错误。人们假设他们有充分的理由允许错误通过,即使没有选择行。我们都同意这是一种不便。
在TRY_CONVERT()
之前,CASE
语句将用于此目的。
【讨论】:
【参考方案3】:首先转换为十进制,然后获取最大(数字)值(因此 10 > 9),然后加 1,然后在必要时转换为字符串。
SELECT
CAST(MAX(CAST(Id AS DECIMAL(38,0))) + 1) AS VARCHAR(39)) AS [New ID]
FROM database
WHERE Id NOT LIKE '%[^0-9]%'
AND LEN(Id) < 39;
【讨论】:
以上是关于选择转换为小数的最大 varchar的主要内容,如果未能解决你的问题,请参考以下文章