SQL Server查找函数

时间:2015-12-11 15:47:53

标签: sql-server sql-server-2012

是否有可能在SQL Server中构建查找类型函数,或者这些函数总是低于(性能)只编写子查询/连接?

我想采取像这样的代码

SELECT
    ContactId,
    ProductType,
    SUM(OrderAmount) TotalOrders
FROM
    (
        SELECT
            ContactId,
            ProductType,
            OrderAmount
        FROM
            UserOrders ord
            JOIN
            (
                SELECT
                    ProductCode,
                    CASE
                        --Complex business logic
                    END ProductType
                FROM
                    ItemTable
            ) item
            ON
                item.ProductCode=ord.ProductCode

    ) a
GROUP BY
    ContactId,
    ProductType

而是能够编写像这样的查询

SELECT
    ContactId,
    UDF_GET_PRODUCT(ProductCode) ProductType,
    SUM(OrderAmount) TotalOrders
FROM
    UserOrders
GROUP BY
    ContactId,
    UDF_GET_PRODUCT(ProductCode)

2 个答案:

答案 0 :(得分:1)

坚持子查询和加入。

因为它将使用基于集合的方法并执行一次内部查询,所以将聚合应用于从内部查询返回的结果集并返回最终结果集。

另一方面,如果您使用类似于第二个查询中显示的标量函数,则将对返回的每一行执行函数内的所有代码(原始问题中的子查询)。

标量函数是性能杀手,应尽可能避免使用它们。这是.net的心态,如果你不得不一次又一次地编写一段代码并将它放在一个方法中并调用该方法,那对于sql server来说就是如此。

答案 1 :(得分:1)

有可能,但不完全符合您所描述的格式。是否合理取决于它。

我同意另一个答案,即标量函数是性能杀手,我个人根本不使用它们。 话虽如此,我认为这不是在可行的情况下忽视DRY原则的理由。即我不会采取捷径 如果它对性能有影响,但我也不喜欢在多个地方重复复杂逻辑的想法。 如果有任何变化,那么您需要更改多个查询,并且不可避免地会有一些错过,所以如果您将重新使用它 逻辑然后将它封装在一个地方是个好主意。

根据您的示例,或许视图最合适:

CREATE VIEW dbo.ItemTableWithLogic
AS
    SELECT  ProductCode,
            ProductType = <your logic>
    FROM    ItemTable;

然后你可以简单地使用:

SELECT  ord.ContactId, item.ProductType, SUM(ord.OrderAmount) AS TotalOrders
FROM    UserOrders AS ord
        INNER JOIN dbo.ItemTableWithLogic AS item
            ON item.ProductCode=ord.ProductCode
GROUP BY ord.ContactId, item.ProductType;

这有点简化了一些事情。

另一种替代方法是内联表值函数,如:

CREATE FUNCTION dbo.GetProductType (@ProductCode INT)
RETURNS TABLE
AS
RETURN
(   SELECT  ProductType = <your logic>
    FROM    ItemTable
    WHERE   ProductCode = @ProductCode
);

可以使用以下方式调用:

SELECT  ord.ContactId, item.ProductType, SUM(ord.OrderAmount) AS TotalOrders
FROM    UserOrders AS ord
        CROSS APPLY dbo.ItemTableWithLogic(ord.ProductCode) AS item
GROUP BY ord.ContactId, item.ProductType;

我的偏好是关于表值函数的观点,但是,它真的取决于你对我推荐的用法,所以我真的不想选择一面,我会坚持坐在围栏上。

总之,如果您只需要在一个地方使用逻辑,并且不需要在许多查询中重用它,那么只需坚持子查询。如果需要多次重复使用相同的逻辑,请不要像在过程语言中那样使用标量值函数,也不要让其排除将逻辑保存在单个位置的其他方法。