sql - 用替代方案替换 SQL Cursor 以提高性能

标签 sql sql-server window-functions cumulative-sum

我正在尝试对以下 Customer_Item View 进行一些处理

<表类=“s-表”> <标题> 客户 ID 金额 项目ID 商品价格 IsActiveStore 优先 <正文> 1 1000 1 100 1 1 1 1000 2 200 1 2 1 1000 3 300 0 3 2 5000 4 4000 1 5 2 5000 5 1100 1 7 2 5000 6 500 1 9

对于每个客户,我想从他的金额中减去按优先级排序的相关商品的价格,并相应地更新每个商品的状态
如果 IsActiveStore 为 false 或金额为零,则跳过该项目

注释:

  • 优先级没有先后顺序,只是按照第二位客户所示的顺序排列
  • 如果按优先级订购的任何商品的价格超过客户的金额(减去之前的商品后),则系统将跳过该商品,并继续处理其余优先级的商品,如第二个客户所示<

所以更新后的客户表应该如下

<表类=“s-表”> <标题> 客户 ID 金额 <正文> 1 700 2 500

更新后的items表应该如下

<表类=“s-表”> <标题> 项目ID 项目状态 <正文> 1 减去 2 减去 3 已跳过 4 减去 5 已跳过 6 减去

现在,我通过使用游标循环遍历客户来完成此操作,对于每个客户,我使用另一个游标循环遍历相关项目,这有效,但对于大数据来说需要很长时间。

有没有更快的替代方法可以有效地进行相同的处理?
提前致谢。

最佳答案

你可以通过CTE来解决它:

WITH cte AS (
    SELECT  *
    FROM
    (
        VALUES  (1, 1000, 1, 100, 1, 1)
        ,   (1, 1000, 2, 200, 1, 2)
        ,   (1, 1000, 3, 300, 0, 3)
        ,   (2, 5000, 4, 1000, 1, 1)
        ,   (2, 5000, 5, 4000, 1, 2)
        ,   (2, 5000, 6, 500, 1, 3)
    ) t (CustomerId,Amount,ItemId,ItemPrice,IsActiveStore,Priority)
)
, cte2 AS (
    SELECT  customerid, CASE WHEN amount < itemprice * isActiveStore THEN 0 ELSE amount - itemprice * isActiveStore END AS amount_left, itemId
    ,   1 AS substracted
    ,   priority
    FROM    cte
    WHERE   priority = 1
    UNION ALL
    SELECT  c.customerid, CASE WHEN c2.amount_left < itemprice * isActiveStore THEN 0 ELSE amount_left - itemprice * isActiveStore END AS amount_left, c.itemid
    ,   CASE WHEN c2.amount_left > 0 AND isActiveStore = 1 THEN 1 ELSE 0 END
    ,   c.priority
    FROM    cte c
    INNER JOIN cte2 c2
        ON  c2.customerid = c.customerid
        AND c2.priority = c.priority - 1
    )
SELECT  customerid, min(amount_left) OVER(partition BY customerid), itemid, CASE substracted WHEN 1 THEN 'substracted' ELSE 'skipped' END
FROM    cte2
OPTION(MAXRECURSION 0)

虽然我不确定它是否会比光标更快,但至少在优先级索引不正确的情况下不会。

CTE 本身非常标准,您创建一个初始金额,然后计算每行的差异。

关于sql - 用替代方案替换 SQL Cursor 以提高性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76972726/

相关文章:

mysql - 如何检查一个组在一列中是否有三个连续的值?

sql - MySQL 嵌套聚合查询,选择特定的中间项

sql - PostgreSQL last_value 忽略空值

mysql - 将 where 子句添加到 MySQL session

sql - 两表三列变一表四列

mysql - 如何将函数的结果存储到变量中?

SQL Filter 日期范围查询

c# - 无效的转换异常?

sql - 如何使用 Visual Studio 2008 Server Explorer 将主键索引重置为 1?

sql - 在T-SQL示例中,为什么在USE db之后有“GO”?