SQL存储过程-返回不同的数据类型

SQL存储过程-返回不同的数据类型,sql,sql-server,stored-procedures,Sql,Sql Server,Stored Procedures,我有一个包含不同数据类型的不同列的表:nvarchar(ISIN),日期(到期日),浮动(息票),int(发行人ID)。 我编写了一个存储过程来返回我输入的任何列。 但是,由于返回数据类型不同,SQL无法编译。 有办法回避这个问题吗 下面的代码: 您需要使用case表达式进行类型转换,但是,concat()将执行您想要的操作: select b.BondID, concat(case when @BondDes = 'IssuerID' then b.IssuerID end,

我有一个包含不同数据类型的不同列的表:
nvarchar(ISIN)
日期(到期日)
浮动(息票)
int(发行人ID)
。 我编写了一个存储过程来返回我输入的任何列。 但是,由于返回数据类型不同,SQL无法编译。 有办法回避这个问题吗

下面的代码:


您需要使用
case
表达式进行类型转换,但是,
concat()
将执行您想要的操作:

select b.BondID, 
       concat(case when @BondDes = 'IssuerID' then b.IssuerID end,
              case when @BondDes = 'ISIN' then b.ISIN end,
              case when @BondDes = 'Coupon' then b.Coupon end,
              case when @BondDes = 'Maturity' then b.Maturity end
             ) as cols
from dbo.Bonds b 
where b.BondID = @BondID;

您需要使用
case
表达式进行类型转换,但是,
concat()
将执行您想要的操作:

select b.BondID, 
       concat(case when @BondDes = 'IssuerID' then b.IssuerID end,
              case when @BondDes = 'ISIN' then b.ISIN end,
              case when @BondDes = 'Coupon' then b.Coupon end,
              case when @BondDes = 'Maturity' then b.Maturity end
             ) as cols
from dbo.Bonds b 
where b.BondID = @BondID;

当前方法的问题是,您将失去所有类型安全性,您需要有一组规则来定义格式,然后让调用程序根据所需的列进行转换

这很麻烦,而且有数据丢失的风险。我建议只返回所有4列,然后让调用者决定如何使用输出

Create procedure dbo.GetBondDes
    @BondID int
As  
    Select Bonds.IssuerID,
            Bonds.ISIN,
            Bonds.Coupon,
            Bonds.Maturity
    From    dbo.Bonds
    Where   dbo.Bonds.BondID = @BondID;
如果出于任何原因想要屏蔽冗余数据,您可以使用:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
    Select  IssuerID = CASE WHEN @BondDes = 'IssuerID' THEN Bonds.IssuerID
            ISIN = CASE WHEN @BondDes = 'ISIN' THEN Bonds.ISIN
            Coupon = CASE WHEN @BondDes = 'Coupon' THEN Bonds.Coupon
            Maturity = CASE WHEN @BondDes = 'Maturity' THEN Bonds.Maturity
    From    dbo.Bonds
    Where   dbo.Bonds.BondID = @BondID;
这将确保为任何不必要的列返回
NULL
(尽管假定
BondID
是主键,但与第一个选项相比,它没有性能优势)

最后,如果您确实只希望返回单个值,则可以使用
if/ELSE
流来维护原始类型:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
    IF @BondDes = 'IssuerID'
    BEGIN
        SELECT  IssuerID AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF @BondDes = 'ISIN'
    BEGIN
        SELECT  ISIN AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF @BondDes = 'Coupon'
    BEGIN
        SELECT  Coupon AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF IF @BondDes = 'Maturity'
    BEGIN
        SELECT  Maturity AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
或者,您可以使用动态SQL,但我建议您在使用时要格外小心:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
BEGIN
    -- CHECK COLUMN EXISTS FIRST
    IF EXISTS (SELECT 1 FROM syy.columns c WHERE c.Name = @BondDes AND object_id = OBJECT_ID(N'dbo.Bonds', 'U'))
    BEGIN
        DECLARE @SQL = CONCAT('SELECT ', QUOTENAME(@BondDes), '  AS Value FROM dbo.Bonds WHERE BondID = @BondID');

        EXECUTE sp_executesql @SQL, N'@BondID INT', @BondID;
    END
END

当前方法的问题是,您将失去所有类型安全性,您需要有一组规则来定义格式,然后让调用程序根据所需的列进行转换

这很麻烦,而且有数据丢失的风险。我建议只返回所有4列,然后让调用者决定如何使用输出

Create procedure dbo.GetBondDes
    @BondID int
As  
    Select Bonds.IssuerID,
            Bonds.ISIN,
            Bonds.Coupon,
            Bonds.Maturity
    From    dbo.Bonds
    Where   dbo.Bonds.BondID = @BondID;
如果出于任何原因想要屏蔽冗余数据,您可以使用:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
    Select  IssuerID = CASE WHEN @BondDes = 'IssuerID' THEN Bonds.IssuerID
            ISIN = CASE WHEN @BondDes = 'ISIN' THEN Bonds.ISIN
            Coupon = CASE WHEN @BondDes = 'Coupon' THEN Bonds.Coupon
            Maturity = CASE WHEN @BondDes = 'Maturity' THEN Bonds.Maturity
    From    dbo.Bonds
    Where   dbo.Bonds.BondID = @BondID;
这将确保为任何不必要的列返回
NULL
(尽管假定
BondID
是主键,但与第一个选项相比,它没有性能优势)

最后,如果您确实只希望返回单个值,则可以使用
if/ELSE
流来维护原始类型:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
    IF @BondDes = 'IssuerID'
    BEGIN
        SELECT  IssuerID AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF @BondDes = 'ISIN'
    BEGIN
        SELECT  ISIN AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF @BondDes = 'Coupon'
    BEGIN
        SELECT  Coupon AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
    ELSE IF IF @BondDes = 'Maturity'
    BEGIN
        SELECT  Maturity AS Value
        FROM    dbo.Bonds
        WHERE   BondID = @BondID ;
    END
或者,您可以使用动态SQL,但我建议您在使用时要格外小心:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
BEGIN
    -- CHECK COLUMN EXISTS FIRST
    IF EXISTS (SELECT 1 FROM syy.columns c WHERE c.Name = @BondDes AND object_id = OBJECT_ID(N'dbo.Bonds', 'U'))
    BEGIN
        DECLARE @SQL = CONCAT('SELECT ', QUOTENAME(@BondDes), '  AS Value FROM dbo.Bonds WHERE BondID = @BondID');

        EXECUTE sp_executesql @SQL, N'@BondID INT', @BondID;
    END
END

返回所有值并让调用者决定他需要哪个值。我同意@user743414的说法,当它们都是同一个表中的列时,我认为只返回1项几乎没有意义。如果您确实只想返回4列中的一列,那么仍然使用4列,但使用4个大小写表达式来删除不需要的数据并返回
NULL
,例如
case WHEN@BondDes='IssuerID然后Bonds.IssuerID结束为IssuerID,
这可能是一个错误,也许有必要提供一些背景知识来解释为什么每次只返回一个值?我正在尝试允许调用方检索特定的值field@TimothyLi我明白你想做什么,我的意思是为什么?如果只给调用者一个字段,而不是全部4个字段,然后让他们决定如何使用这4个字段,你会得到什么?您可以将它们全部转换为相同的数据类型,但是调用者将丢失任何类型信息,并且需要将它们转换回,这可能是不正确的。所以你想做的是可能的,但这几乎肯定不是解决你问题的正确方法。@GarethD谢谢你的反馈。经过一些思考,我同意你的看法。返回所有值并让调用者决定他需要哪个值。我同意@user743414,当它们都在同一个表中时,我认为只返回1项几乎没有意义。如果您确实只想返回4列中的一列,那么仍然使用4列,但使用4个大小写表达式来删除不需要的数据并返回
NULL
,例如
case WHEN@BondDes='IssuerID然后Bonds.IssuerID结束为IssuerID,
这可能是一个错误,也许有必要提供一些背景知识来解释为什么每次只返回一个值?我正在尝试允许调用方检索特定的值field@TimothyLi我明白你想做什么,我的意思是为什么?如果只给调用者一个字段,而不是全部4个字段,然后让他们决定如何使用这4个字段,你会得到什么?您可以将它们全部转换为相同的数据类型,但是调用者将丢失任何类型信息,并且需要将它们转换回,这可能是不正确的。所以你想做的是可能的,但这几乎肯定不是解决你问题的正确方法。@GarethD谢谢你的反馈。经过一些思考,我同意你的看法。这是因为
concat()
忽略
NULL
值(而不是返回
NULL
)。也就是说,您可能希望通过显式类型转换来控制结果的格式,尤其是日期。这是因为
concat()
忽略
NULL
值(而不是返回
NULL
)。也就是说,您可能希望通过显式类型转换来控制结果的格式,尤其是日期。您就是一个图例。谢谢你的支持,你是一个传奇。谢谢你所有富有洞察力的支持。