2012-08-08 79 views
1

SQL是新手,经验丰富的VBA-er需要一些帮助。SQL Server:在功能中使用案例

我有一个查看交易,需要获得特定类型的不同费用。费用列表中需要一些字段,其他字段可能为NULL。通过这种方式,我们可以设置一般收费结构,并仍然允许特定的特殊功能。

我现在的目标是找到最佳匹配费用。这是费:

  1. 匹配所有要求的标准,
  2. 匹配所有可选的标准或者已经NULL对他们来说,
  3. 拥有的是通过1和2
  4. 所有费用最匹配的可选条件

现在我得到了这个代码的工作版本,但作为一个PROCEDURE。然而,因为我需要这个在视图中使用,我不能使用该版本,并且在函数中没有允许临时表)。

寻找在这个论坛和其他人后,我来到了一个结果仍然给2个错误:
1的ErrorMessage:近'@tblTEMP'不正确的语法,
2的ErrorMessage:近'BEGIN'不正确的语法。

我当前的脚本如下(使用本地变量表):

ALTER FUNCTION [dbo].[fnStandardFeeBAK] 
    (@Type_Id BIGINT, @Party_Id BIGINT, @I_A_Id BIGINT, @Grid_Id BIGINT, 
    @Market_Id BIGINT, @Counterparty_Id BIGINT, @Product_Id BIGINT, 
    @DealDate DATETIME) 
RETURNS TABLE 

AS 

BEGIN 
    DECLARE @tblTEMP TABLE (Standard_Fee DECIMAL(38,8), Currency VARCHAR(50), 
    Unit VARCHAR(50), Unit2 VARCHAR(50), MatchScore BIGINT); 
    WITH @tblTEMP AS 
    (SELECT Standard_Fee, V2.Element AS Currency, V1.Element AS Unit, 
V2.Element+'/'+V1.Element AS Unit2, 
    SF.I_A_Id, SF.Grid_Id, SF.Product_Id, SF.Counterparty_Id, 
    (CASE WHEN SF.I_A_Id = @I_A_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Grid_Id = @Grid_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Product_Id = @Product_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Counterparty_Id = @Counterparty_Id THEN 1 ELSE 0 END) 
     AS MatchScore 
    FROM tblStandard_Fee AS SF 
    LEFT JOIN tblElement AS V1 ON V1.Element_Id = SF.Unit_Id 
    LEFT JOIN tblElement AS V2 ON V2.Element_Id = SF.Currency_Id 

    WHERE SF.Type_Id = @Type_Id AND SF.Party_Id = @Party_Id AND 
    SF.Market_Id = @Market_Id 
    AND SF.Date_From < @DealDate 
    AND (SF.Date_To > @DealDate OR SF.Date_To IS NULL) 
    AND (SF.I_A_Id = @I_A_Id OR SF.I_A_Id IS NULL) 
    AND (SF.Grid_Id = @Grid_Id OR SF.Grid_Id IS NULL) 
    AND (SF.Product_Id = @Product_Id OR SF.Product_Id IS NULL) 
    AND (SF.Counterparty_Id = @Counterparty_Id OR SF.Counterparty_Id IS NULL)) 
RETURN 
    SELECT Standard_Fee, Currency, Unit, Unit2 
    FROM @tblTEMP 
    WHERE MatchScore= MAX(MatchScore) 
END 

我希望我的问题是清楚的,如果不是让我知道。

感谢您提出建议,甚至用最后一点来解决我的问题!


因此,所有的LittleBobbyTables的帮助相结合给了我一个工作的最终结果。请不要忘记给他这个信用。

工作代码:

ALTER FUNCTION [dbo].[fnStandardFeeBAK] 
(@Type_Id BIGINT, @Party_Id BIGINT, @I_A_Id BIGINT, @Grid_Id BIGINT, 
@Market_Id BIGINT, @Counterparty_Id BIGINT, @Product_Id BIGINT, @DealDate DATETIME) 

RETURNS @YourTable TABLE 
(
    -- Columns returned by the function 
    Standard_Fee DECIMAL(38,8), 
    Currency VARCHAR(50), 
    Unit VARCHAR(50), 
    Unit2 VARCHAR(50) 
) 
AS 

BEGIN 
    WITH YourCTE(Standard_Fee, Currency, Unit, Unit2, MatchScore) AS 
    (
    SELECT Standard_Fee, V2.Element AS Currency, V1.Element AS Unit, 
     V2.Element + '/' + V1.Element AS Unit2, 
     (CASE WHEN SF.I_A_Id = @I_A_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Grid_Id = @Grid_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Product_Id = @Product_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Counterparty_Id = @Counterparty_Id THEN 1 ELSE 0 END) 
     AS MatchScore 
    FROM tblStandard_Fee AS SF 
     LEFT JOIN tblElement AS V1 ON V1.Element_Id = SF.Unit_Id 
     LEFT JOIN tblElement AS V2 ON V2.Element_Id = SF.Currency_Id 

    --Type_ID, Party_ID and Market_Id are always present, others can have NULL values 
    WHERE SF.Type_Id = @Type_Id AND SF.Party_Id = @Party_Id 
      AND SF.Market_Id = @Market_Id AND SF.Date_From < @DealDate 
      AND (SF.Date_To > @DealDate OR SF.Date_To IS NULL) 
      AND (SF.I_A_Id = @I_A_Id OR SF.I_A_Id IS NULL) 
      AND (SF.Grid_Id = @Grid_Id OR SF.Grid_Id IS NULL) 
      AND (SF.Product_Id = @Product_Id OR SF.Product_Id IS NULL) 
      AND (SF.Counterparty_Id = @Counterparty_Id OR SF.Counterparty_Id IS NULL) 
    GROUP BY Standard_Fee, V1.Element, V2.Element, SF.I_A_Id, SF.Grid_Id, SF.Product_Id, SF.Counterparty_Id 
    ) 
    INSERT @YourTable 
     SELECT Standard_Fee, Currency, Unit, Unit2 
     FROM YourCTE 
     GROUP BY MatchScore, Standard_Fee, Currency, Unit, Unit2 
     HAVING MatchScore = (SELECT MAX(MatchScore) FROM YourCTE) 

    RETURN; 
END 
+0

我现在看到我有'SF.I_A_Id,SF.Grid_Id,SF.Product_Id,SF.Counterparty_Id,'仍然在我的代码中的第一选择声明。但即使采取这种做法也不会摆脱错误 – 2012-08-08 13:53:26

回答

2

Table-Valued User-Defined Functions文档中,正确的语法是:

ALTER FUNCTION dbo.fnStandardFeeBAK(@Type_Id BIGINT, @Party_Id BIGINT, 
    @I_A_Id BIGINT, @Grid_Id BIGINT, @Market_Id BIGINT, 
    @Counterparty_Id BIGINT, @Product_Id BIGINT, 
    @DealDate DATETIME) 

RETURNS @YourTable TABLE 
(
    -- Columns returned by the function 
    Standard_Fee DECIMAL(38,8), 
    Currency VARCHAR(50), 
    Unit VARCHAR(50), 
    Unit2 VARCHAR(50) 
) 
AS 

,并在结尾:

INSERT @YourTable 
    SELECT Standard_Fee, Currency, Unit, Unit2 
    FROM YourCTE 
    WHERE MatchScore= MAX(MatchScore) 
    RETURN; 
END; 

编辑:搞砸CTE,你不需要临时表。

把它放在一起,你会得到:

ALTER FUNCTION dbo.fnStandardFeeBAK(@Type_Id BIGINT, @Party_Id BIGINT, 
    @I_A_Id BIGINT, @Grid_Id BIGINT, @Market_Id BIGINT, 
    @Counterparty_Id BIGINT, @Product_Id BIGINT, 
    @DealDate DATETIME) 

RETURNS @YourTable TABLE 
(
    -- Columns returned by the function 
    Standard_Fee DECIMAL(38,8), 
    Currency VARCHAR(50), 
    Unit VARCHAR(50), 
    Unit2 VARCHAR(50) 
) 
AS 

BEGIN 
WITH YourCTE (Standard_Fee, Currency, Unit, Unit2, MatchScore) AS 
    (SELECT Standard_Fee, V2.Element AS Currency, V1.Element AS Unit, 
V2.Element+'/'+V1.Element AS Unit2, 
    SF.I_A_Id, SF.Grid_Id, SF.Product_Id, SF.Counterparty_Id, 
    (CASE WHEN SF.I_A_Id = @I_A_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Grid_Id = @Grid_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Product_Id = @Product_Id THEN 1 ELSE 0 END + 
     CASE WHEN SF.Counterparty_Id = @Counterparty_Id THEN 1 ELSE 0 END) 
     AS MatchScore 
    FROM tblStandard_Fee AS SF 
    LEFT JOIN tblElement AS V1 ON V1.Element_Id = SF.Unit_Id 
    LEFT JOIN tblElement AS V2 ON V2.Element_Id = SF.Currency_Id 

    WHERE SF.Type_Id = @Type_Id AND SF.Party_Id = @Party_Id AND 
    SF.Market_Id = @Market_Id 
    AND SF.Date_From < @DealDate 
    AND (SF.Date_To > @DealDate OR SF.Date_To IS NULL) 
    AND (SF.I_A_Id = @I_A_Id OR SF.I_A_Id IS NULL) 
    AND (SF.Grid_Id = @Grid_Id OR SF.Grid_Id IS NULL) 
    AND (SF.Product_Id = @Product_Id OR SF.Product_Id IS NULL) 
    AND (SF.Counterparty_Id = @Counterparty_Id OR SF.Counterparty_Id IS NULL)) 

    INSERT @YourTable 
    SELECT Standard_Fee, Currency, Unit, Unit2 
    FROM YourCTE 
    WHERE MatchScore= MAX(MatchScore) 
    RETURN; 
END; 
+0

第二个错误肯定是与这些变化一起消失了,谢谢你!不幸的是,我仍然在本地变量TABLE上留下了一个错误。它与'使用@tblTEMP AS'相关# – 2012-08-08 13:40:54

+0

@K_B - 我删除了临时表,并创建了一个标准的CTE。 – LittleBobbyTables 2012-08-08 13:46:49

+0

我已经应用了这一点,并且还取出了'SF.I_A_Id,SF.Grid_Id,SF.Product_Id,SF.Counterparty_Id'行中的多余项目,但是它现在会给出错误:'ErrorMessage:聚合可能不会出现在WHERE除非它位于包含在HAVING子句或选择列表中的子查询中,并且要汇总的列是外部引用。' – 2012-08-08 13:56:56