在没有引号 T-SQL / SQL Server 2012 的函数中传递值?

Posted

技术标签:

【中文标题】在没有引号 T-SQL / SQL Server 2012 的函数中传递值?【英文标题】:Passing value in a function without quote T-SQL / SQL Server 2012? 【发布时间】:2017-09-25 21:33:52 【问题描述】:

我需要帮助我在 SQL Server 2012 中创建用于检查输入值的函数。如果函数检测到数字 - 返回 0,如果检测到字符返回 1。

但是对于相同的数字,我得到了 2 个不同的结果,无论是带引号还是不带引号。

select dbo.IS_ALIEN('56789')

返回 0

select dbo.IS_ALIEN(56789)

返回 1(我需要返回 0)

这是我的功能:

ALTER FUNCTION [dbo].[IS_ALIEN] 
    (@alienNAIC CHAR(1))
RETURNS NUMERIC(10,0) 
AS
BEGIN
    DECLARE @nNum NUMERIC(1,0);

    BEGIN
        SET @NnUM = ISNUMERIC(@alienNAIC)
    END
    BEGIN
        IF @nNum = 1 
            RETURN 0;
        END

        RETURN 1;
    END

同样的概念:

select  dbo.IS_ALIEN('AA-11990043')

返回 1

select  dbo.IS_ALIEN(NULL)

返回 1(我需要它返回 0)

我正在使用 Oracle 函数参考(以下代码仅来自旧数据库的参考):

create or replace FUNCTION "IS_ALIEN" 
  (  alienNAIC IN char )
  RETURN  NUMBER IS
  nNum number;
BEGIN
    SELECT MOD(alienNAIC, 2) into nNum FROM dual;
    return 0;
EXCEPTION
WHEN INVALID_NUMBER THEN
    return 1;
END;

但是 T-SQL 函数不允许出错异常。所以我尝试转换更接近。

【问题讨论】:

提示:在 management studio 中运行SELECT CAST(56789 As CHAR(1)) 并检查结果。这是 Sql Server 在您的任何代码运行之前就将其转换为您的参数类型的问题。听起来您需要使用 sql_variant 类型解决问题,这并不容易。 啊,我得到一个星号 (*) 始终使用标签指定服务器的版本。如果您使用的是 2008 及更高版本,则可以使用 ISNUMERIC 函数。顺便说一句,当您将@alienNAIC char(1) 定义为参数时,它只需要输入的第一个字符。 感谢我修改了标题,它是 sql server 2012。是的,我正在尝试检查是否为空、数字或字母。该字段将收到 Null 或 Number 或 AA。所以如果是 AA,它是一个外星人,所以返回 1。如果是数字或 null,则表示不是外星人,返回 0。但我没有像在 Oracle 中那样得到这些结果。 看起来您使用的是 Oracle,但您使用 tsql 进行了标记。顺便说一句,如果目的是检查外星人,您只需要检查前 2 个字母并确保它们是“AA”。然后删除“AA-”并确保剩余部分是数字。我不确定为什么你有这种方法来实现这一点。请修复标签。 【参考方案1】:

我建议你使用这样的东西(我已经把它剪掉了一些):

ALTER FUNCTION [dbo].[IS_ALIEN](@alienNAIC NVARCHAR(10))
RETURNS INT -- NOTE: You could also return tinyint or bit
AS
BEGIN
    IF ISNUMERIC(@alienNAIC) = 1 
        RETURN 0;

    RETURN 1;
END

您尝试的问题在于CHAR(1) 的隐式转换,其结果绝对不是@Joel 指出的数字:

SELECT CAST(0 As CHAR(1)) -- returns character '0', ISNUMERIC(0) = 1
SELECT CAST(9 As CHAR(1)) -- returns character '9', ISNUMERIC(0) = 1
SELECT CAST(12345 As CHAR(1)) -- any number over 9 returns character '*', ISNUMERIC(12345) = 0

这是我以前从未见过的奇怪的隐式转换案例。通过将参数设为NVARCHAR(假设将来可能输入双字节),将正确检查字符串并将传入的整数隐式转换为NVARCHAR,并且ISNUMERIC 检查将成功。

编辑 重新阅读问题和 cmets,您似乎想要识别特定的字符串语法以确定某物是否是“外星人”。如果您愿意更改业务逻辑以解决显然是糟糕的遗留实现,您可以考虑这样的事情:

ALTER FUNCTION [dbo].[temp](@alienNAIC NVARCHAR(10))
RETURNS INT -- NOTE: You could also return tinyint or bit
AS
BEGIN
    IF @alienNAIC like 'AA-%' AND ISNUMERIC(RIGHT(@alienNAIC, LEN(@alienNAIC) - 3)) = 1
        RETURN 1; -- notice this is now 1 instead of 0, we're doing a specific check for 'AA-nnnnn...'

    RETURN 0;
END

请注意,如果要与旧数据交互,则应针对旧数据进行彻底测试 - 您永远不知道编写不佳的旧系统留下了哪些垃圾数据。解决这个问题很可能会破坏其他事情。如果您确实进行了此更改,请做好记录。

【讨论】:

感谢您对本次修复所做的更改。这就是我要找的。​​span> 【参考方案2】:

如果您只需要检查第一个字符,那么您可以这样做:

CREATE FUNCTION [dbo].[IS_ALIEN] 
    (@alienNAIC VARCHAR(200))
RETURNS TINYINT 
AS
BEGIN
    IF LEFT(@alienNAIC,1) BETWEEN '0' AND '9' RETURN 1;
    RETURN 0
END
GO

【讨论】:

【参考方案3】:

您似乎正在尝试检查字符串是否以非数字字符开头。可以使用LIKE 执行此类模式匹配,例如

declare @var nvarchar(10)='A56789'

select 
    case when @var LIKE '[0-9]%' 
         then 0 else 1 
    end AS IsAlien

返回

1

declare @var nvarchar(10)=56789declare @var int=56789 都返回 0,因为该数字已隐式转换为字符串。

表达式很短,您可能不需要将其转换为函数。如果你这样做,它可能很简单:

create FUNCTION [dbo].[IS_ALIEN]  (@alienNAIC varchar(200))
RETURNS INT 
begin 
    return  case when @alienNAIC LIKE '[0-9]%' 
                             then 0 else 1 
                        end 

end

如果要在 WHERE 子句中执行检查,只需使用LIKE,而不是任何函数,例如:

WHERE alienNAIC NOT LIKE '[0-9]%'

这个特定的模式只是一个范围搜索,涵盖了09...... 之间的所有值。服务器可以使用覆盖文本列的索引来快速识别匹配项。当它必须检查函数的 result 时,它不能这样做。它必须在过滤之前计算每一行的值。

【讨论】:

以上是关于在没有引号 T-SQL / SQL Server 2012 的函数中传递值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 T-SQL 中的 XML 字符串中的属性中转义双引号?

SQL Server 2005 T-SQL中的Base64编码

使用 SSIS OR T-SQL 将一列带引号和不带引号的逗号分隔值拆分为多列

SQL Server (T-SQL) BAIv2 银行文件导入噩梦

T-SQL查询高级—SQL Server索引中的碎片和填充因子

SQL Server 2008 T-SQL UDF Split() 剪裁