我的表有两个sql_variant
列。在第一列中,将十进制值作为varchar插入。在第二列中,十进制值作为十进制自身插入。
DECLARE @ATempSelected TABLE(RowNum [int] ,Quantity1 sql_variant,
Quantity2 sql_variant)
INSERT INTO @ATempSelected
SELECT 1, '18.33',18.33
UNION ALL
SELECT 2, '18.555555',18.555555
只有当比例小于或等于2时,才应将sql_variant转换为十进制ResultantValue。否则我需要在ResultantValue中显示-1。我有以下案例陈述。
SELECT T.Quantity1,
SQL_VARIANT_PROPERTY(T.Quantity1,'Scale') ScaleValue1,
CASE WHEN SQL_VARIANT_PROPERTY(T.Quantity1,'Scale') <= 2 THEN CONVERT(DECIMAL(8,2),T.Quantity1) ELSE -1 END AS ResultantValue1,
T.Quantity2,
SQL_VARIANT_PROPERTY(T.Quantity2,'Scale') ScaleValue2,
CASE WHEN SQL_VARIANT_PROPERTY(T.Quantity2,'Scale') <= 2 THEN CONVERT(DECIMAL(8,2),T.Quantity2) ELSE -1 END AS ResultantValue2
FROM @ATempSelected T
SQL_VARIANT_PROPERTY为值{18 .555555'提供scale
零。
SQL Server 2012
中上述逻辑的最佳方法是什么(如果比例大于2,则显示-1)?
注意:输入的实际值将是整数或十进制(但作为varchar接收)。在客户端应用程序中,此验证已在此代码之前的步骤中实施。我只需要验证scale
。
答案 0 :(得分:1)
Quantity1是varchar,因此默认比例为0&gt;&gt;&gt; &#34;所有其他类型&#34; &LT;&LT;&LT;
Scale decimal (p,s) and numeric (p,s) = s
money and smallmoney = 4
datetime = 3
all other types = 0
要切换,也许
IIF(SQL_VARIANT_PROPERTY(T.Quantity2,'Scale')>2,-1,SQL_VARIANT_PROPERTY(T.Quantity2,'Scale')),
修改强>
只是因为你让我很好奇,我创建了一个UDF来返回比例。这样您就可以返回记录级别。
编辑2:添加了删除尾随零的选项
CREATE FUNCTION [dbo].[udf-Stat-Scale](@Value varchar(50),@Strip0s Bit)
Returns int
Begin
Declare @Rev varchar(50) = Reverse(@Value)
Declare @Ret int = IIF(@Strip0s=0, CharIndex('.',@Rev)-1,CharIndex('.',Substring(@Rev, PatIndex('%[^0]%', @Rev+'.'), LEN(@Value)))-1)
Return IIF(@Ret<0,0,@Ret)
End
样本结果
Select [dbo].[udf-Stat-Scale](18.250,1) Returns 2
Select [dbo].[udf-Stat-Scale](18.250,0) Returns 3
Select [dbo].[udf-Stat-Scale]('18.1234',1) Returns 4
答案 1 :(得分:1)
varchar
没有比例......
对于通用方法,使用字符串方法更容易获得缩放长度:
DECLARE @ATempSelected TABLE(RowNum [int] ,Quantity1 sql_variant,
Quantity2 sql_variant)
INSERT INTO @ATempSelected
SELECT 1, '18.33',18.33
UNION ALL
SELECT 2, '18.555555',18.555555;
SELECT T.*
,ScaleLength.*
FROM @ATempSelected AS T
CROSS APPLY(SELECT CAST(Quantity1 AS VARCHAR(100)) AS q1
,CAST(Quantity2 AS VARCHAR(100)) AS q2) AS AllText
CROSS APPLY(SELECT LEN(AllText.q1)-CHARINDEX('.',AllText.q1) AS Scale1
,LEN(AllText.q1)-CHARINDEX('.',AllText.q2) AS Scale2 ) AS ScaleLength
如果末尾有字符串值为零,则可以使用REVERSE
和PATINDEX
从右侧找到除零之外的第一个字符,并将此部分剪掉。然后重新反转字符串......
答案 2 :(得分:0)
以下是我现在使用的内容,直到我得到更好的答案。
DECLARE @ATempSelected TABLE(RowNum [int] ,Quantity1 VARCHAR(100), NewQuantity VARCHAR(100))
INSERT INTO @ATempSelected(RowNum,Quantity1)
SELECT 1, '18.33'
UNION ALL
SELECT 2, '18.555555'
UNION ALL
SELECT 3, '18'
UNION ALL
SELECT 4, '17.'
UNION ALL
SELECT 5, '16.1'
UNION ALL
SELECT 6, '1234567.1'
UNION ALL
SELECT 7, '1234567'
UNION ALL
SELECT 8, 'A'
UNION ALL
SELECT 8, '1e4'
UPDATE @ATempSelected SET NewQuantity = Quantity1
WHERE ISNUMERIC(Quantity1 + 'e0') = 1
UPDATE @ATempSelected SET NewQuantity = '-1'
WHERE ISNUMERIC(Quantity1 + 'e0') = 0
SELECT T.Quantity1,T.NewQuantity,
--,ScaleLength.*,
LEN(T.NewQuantity) AS LengthOfString,
CHARINDEX('.',T.NewQuantity) as IndexVal,
CASE WHEN CHARINDEX('.',T.NewQuantity) > 0 THEN LEN(T.NewQuantity)-CHARINDEX('.',T.Quantity1) ELSE 0 END AS Scale,
CASE WHEN CHARINDEX('.',T.NewQuantity) > 0 THEN (LEN(T.NewQuantity) - (LEN(T.NewQuantity)-CHARINDEX('.',T.NewQuantity))-1) ELSE LEN(T.NewQuantity) END AS NumericPart
,CASE
WHEN CHARINDEX('.',T.NewQuantity) = 0 AND LEN(T.NewQuantity) <= 6 THEN CONVERT(DECIMAL(8,2),T.NewQuantity) --No decimal places
WHEN CHARINDEX('.',T.NewQuantity) = 0 AND LEN(T.NewQuantity) > 6 THEN -1 --No decimal places; but exceeds the numbers in numeric part
WHEN LEN(T.NewQuantity)-CHARINDEX('.',T.NewQuantity) <= 2
AND (LEN(T.NewQuantity) - (LEN(T.NewQuantity)-CHARINDEX('.',T.NewQuantity))-1) <= 6
THEN CONVERT(DECIMAL(8,2),T.NewQuantity) --Decimal places present + Scale is 2 or less + Numeric Part is 6 or less
ELSE -1
END AS Result
FROM @ATempSelected AS T