如果比例大于2,则显示-1

时间:2016-07-24 00:56:19

标签: sql-server

我的表有两个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

enter image description here

3 个答案:

答案 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 

如果末尾有字符串值为零,则可以使用REVERSEPATINDEX从右侧找到除零之外的第一个字符,并将此部分剪掉。然后重新反转字符串......

答案 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