使用declare语句的T-SQL表函数

时间:2014-03-13 15:55:23

标签: sql sql-server tsql table-functions

我有以下我正在构建的SQL语句,它根据表中的值的顺序返回一系列值,用于'产品数据'

例如,产品,电视,具有屏幕尺寸,我们希望根据用户配置在具有指定范围之间的屏幕的电视上进行查询。所以他们可能会说,给我替代电视3个尺寸,两边都是42"。

此查询仅根据指定的产品执行此操作:

DECLARE @ProductType INT = (
                             SELECT p.prod_ptype_id
                                FROM product p
                                WHERE p.prod_id = @ProductId
                           )
DECLARE @AttributeId INT = (
                             SELECT at.aptype_attr_id
                                FROM Attribute_ProductType at
                                INNER JOIN Attribute a
                                    ON a.attr_id = at.aptype_attr_id
                                WHERE ISNULL(a.ReplacementTolerant, 0) = 1
                                    AND at.aptype_ptype_id = @ProductType
                           )
DECLARE @ToleranceRange INT = (
                                SELECT a.ToleranceRange
                                    FROM Attribute_ProductType at
                                    INNER JOIN Attribute a
                                        ON a.attr_id = at.aptype_attr_id
                                    WHERE ISNULL(a.ReplacementTolerant, 0) = 1
                                        AND at.aptype_ptype_id = @ProductType
                              )
DECLARE @AttributeValueIndex INT = (
                                     SELECT DISTINCT ( av.attrval_index )
                                        FROM Product_Attribute pa
                                        INNER JOIN AttributeValue av
                                            ON av.attrval_attr_id = pa.pattr_attr_id
                                        WHERE av.attrval_id = (
                                                                SELECT pattr_attrval_id
                                                                    FROM product_attribute pa3
                                                                    WHERE pa3.pattr_prod_id = @ProductId
                                                                        AND pa3.pattr_attr_id = @AttributeId
                                                              )
                                   );


WITH    ProductTypeAttributes
          AS (
               SELECT DISTINCT attrval_val
                   ,attrval_index
                   ,ROW_NUMBER() OVER ( ORDER BY attrval_index ) AS RowNumber
                FROM Product_Attribute pa
                INNER JOIN AttributeValue av
                    ON av.attrval_id = pa.pattr_attrval_id
                INNER JOIN Product p
                    ON p.prod_id = pa.pattr_prod_id
                WHERE pa.pattr_attr_id = @AttributeId
                    AND p.prod_ptype_id = @ProductType
                GROUP BY attrval_val
                   ,attrval_index
             )
    SELECT *
        FROM ProductTypeAttributes
        WHERE RowNumber >= (
                             (SELECT DISTINCT ( RowNumber )
                                FROM ProductTypeAttributes pta2
                                WHERE attrval_index = @AttributeValueIndex)
                           ) - @ToleranceRange
            AND ( RowNumber <= (
                                 SELECT DISTINCT ( RowNumber )
                                    FROM ProductTypeAttributes pta3
                                    WHERE attrval_index = @AttributeValueIndex
                               ) + @ToleranceRange )

这一切都很好,并且完全按照我需要的方式工作,虽然它可能需要一些优化,但是现在我只是希望能够将它作为POC所需要的地方。 / p>

显而易见的选择是将其作为一个表格功能 - 但是当我有这些声明时,我不知道要应用什么语法?#39;声明&#39;语句。

我已经查看了MSDN和样本,这些样本显示了我认为需要实现的类似样本,但我无法理解如何将declare语句与表结合使用以这种方式运作。

任何人都可以对此有所了解吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

我无法在我愿意投入的时间内将整个查询快速转换为内联函数,尤其是在不了解表中的内容及其相关性的情况下。但是,我相信我在下面的内容至少会替换你的前4个选项,并且可以重复使用。我相信使用相同的概念你可以将查询的其余部分合并到这个函数中 - 或者可能是第二个函数用于更多的模块化。在尝试转换之前,最好先进行优化。

CREATE FUNCTION  GetProductInfo
(
    @ProductID int
)

RETURNS TABLE
AS
    RETURN
        SELECT
            p.prod_ptype_id AS ProductType,
            at.aptype_attr_id AS AttributeId,
            a.ToleranceRange AS ToleranceRange
            av.attrval_index AS AttributeValueIndex
        FROM        product p
        INNER JOIN  Attribute_ProductType at
        ON          at.aptype_ptype_id = p.prod_ptype_id
        INNER JOIN  Attribute a
        ON          a.attr_id = at.aptype_attr_id
        AND         a.ReplacementTolerant = 1
        -- This next section got a little confusing for me. Knowing more about what is in the various tables would help me figure out which tables
        --      might produce duplicate rows requiring the CROSS APPLY TOP 1 construct and which could be simple JOINs.
        -- Also, you are using Product_Attribute twice in the same query for @AttributeValueIndex in a confusing (to me) way, so I attempted to simplify here.
        CROSS APPLY (
                        SELECT
                            TOP 1 *
                        FROM        product_attribute pa_all
                        WHERE       pa_all.pattr_prod_id = p.prod_ptype_id
                        AND         pa_all.pattr_attr_id = at.aptype_attr_id
                    ) AS pa
        INNER JOIN  AttributeValue av
        ON          av.attrval_attr_id = pa.pattr_attr_id
        AND         av.attrval_id = pa.pattr_attrval_id
        WHERE       p.prod_id = @ProductId;

GO

DECLARE
    @ProductType INT
    @AttributeId INT
    @ToleranceRange INT,
    @AttributeValueIndex INT;
SELECT
    @ProductType = ProductType,
    @AttributeId = AttributeId,
    @ToleranceRange = ToleranceRange,
    @AttributeValueIndex = AttributeValueIndex
FROM        GetProductInfo
            (
                @ProductID
            );

答案 1 :(得分:0)

部署我以前的评论,而不是内联,我最终使用了多语句表函数:

CREATE FUNCTION GetAttributeToleranceRange
(   
    @ProductId int
)
RETURNS @ProductTypeToleranceRange TABLE
(
    prod_type int,
    attr_id int,
    attrval_val nvarchar(max),
    attrval_index int, 
    RowNumber int
)
AS BEGIN

    DECLARE @ProductTypeAttributesTable TABLE
    (
        attrval_val nvarchar(max),
        attrval_index int, 
        RowNumber int
    )

    declare @ProductType int
    declare @AttributeId int 
    declare @ToleranceRange int 
    declare @AttributeValueIndex int 

    SELECT @ProductType = (SELECT p.prod_ptype_id FROM product p WHERE p.prod_id=@ProductId)

    SELECT @AttributeId = (SELECT at.aptype_attr_id FROM Attribute_ProductType at INNER JOIN Attribute a ON a.attr_id = at.aptype_attr_id WHERE ISNULL(a.ReplacementTolerant,0)=1 AND at.aptype_ptype_id = @ProductType)
    SELECT @ToleranceRange = (SELECT a.ToleranceRange FROM Attribute_ProductType at INNER JOIN Attribute a ON a.attr_id = at.aptype_attr_id WHERE ISNULL(a.ReplacementTolerant,0)=1 AND at.aptype_ptype_id = @ProductType)
    SELECT @AttributeValueIndex = (SELECT DISTINCT(av.attrval_index) FROM Product_Attribute pa INNER JOIN AttributeValue av ON av.attrval_attr_id=pa.pattr_attr_id WHERE av.attrval_id = (SELECT pattr_attrval_id FROM product_attribute pa3 WHERE pa3.pattr_prod_id=@ProductId and pa3.pattr_attr_id=@AttributeId));

    INSERT @ProductTypeAttributesTable SELECT DISTINCT attrval_val, attrval_index, ROW_NUMBER() OVER (ORDER BY attrval_index) As RowNumber
    FROM Product_Attribute pa 
    INNER JOIN AttributeValue av ON av.attrval_id = pa.pattr_attrval_id
    INNER JOIN Product p ON p.prod_id = pa.pattr_prod_id
    WHERE pa.pattr_attr_id = @AttributeId AND p.prod_ptype_id = @ProductType
    GROUP BY attrval_val, attrval_index;

    INSERT @ProductTypeToleranceRange SELECT @ProductType, @AttributeId, * FROM @ProductTypeAttributesTable WHERE RowNumber >= ((SELECT DISTINCT(RowNumber) FROM @ProductTypeAttributesTable pta2 WHERE attrval_index=@AttributeValueIndex)) - @ToleranceRange AND (RowNumber <= (SELECT DISTINCT(RowNumber) FROM @ProductTypeAttributesTable pta3 WHERE attrval_index=@AttributeValueIndex) + @ToleranceRange)
    RETURN
END

同样,它会从一些优化中受益,但它确实在我需要的地方使用单一参数时可以提供我需要的东西。