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
)。也就是说,您可能希望通过显式类型转换来控制结果的格式,尤其是日期。您就是一个图例。谢谢你的支持,你是一个传奇。谢谢你所有富有洞察力的支持。