SQL Хранимая процедура - возврат разных типов данных - PullRequest
0 голосов
/ 19 марта 2020

У меня есть таблица разных столбцов разных типов данных: nvarchar (ISIN), date (maturity), float (Coupon), int (IssuerID). Я написал хранимую процедуру для возврата любого столбца, который я ввел. Однако, поскольку тип возвращаемых данных отличается, SQL не может быть скомпилирован. Есть ли способ обойти эту проблему?

Код ниже:

Create procedure dbo.GetBondDes
    @BondID int,
    @BondDes nvarchar(50)
As  
    Select 
    (
    Case
        When @BondDes = 'IssuerID' Then Bonds.IssuerID
        When @BondDes = 'ISIN' Then Bonds.ISIN
        When @BondDes = 'Coupon' Then Bonds.Coupon
        When @BondDes = 'Maturity' Then Bonds.Maturity
    End) 
    From dbo.Bonds
    Where dbo.Bonds.BondID = @BondID

Ответы [ 2 ]

2 голосов
/ 19 марта 2020

Вам нужно преобразование типа с выражением 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;
0 голосов
/ 19 марта 2020

Проблема, с которой вы столкнетесь при текущем подходе, заключается в том, что вы потеряете всю безопасность типов, вам потребуется набор правил для определения форматов, а затем обратный вызов вызывающей стороны на основе требуемого столбца.

Это громоздко и может привести к потере данных. Я бы предложил просто вернуть все 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

Или вы можете использовать Dynami c 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
...