将游标转换为基于 SET 的操作的 T-SQL 问题

发布于 2024-10-01 02:13:42 字数 1746 浏览 3 评论 0原文

基本上我有一个不是我写的光标,但需要一些时间来处理,我想通过一起摆脱光标来尝试和改进它。

代码如下:

DECLARE @class_id int, @title_code varchar(30)

DECLARE title_class CURSOR FOR
SELECT DISTINCT title_code FROM tmp_business_class_titles (NOLOCK)

OPEN title_class

    FETCH title_class INTO @title_code

    WHILE @@FETCH_STATUS = 0
        BEGIN
            SELECT TOP 1 @class_id = bc1.categoryid
            FROM tmp_business_class_titles bct, 
            dbo.Categories bc1 (nolock) 
            join dbo.Categories bc2 (nolock) on bc2.categoryid = bc1.highercategoryid
            join dbo.Categories bc3 (nolock) on bc3.categoryid = bc2.highercategoryid 
            WHERE bc1.categoryid = bct.class_id
                AND title_code = @title_code
            ORDER BY Default_Flag DESC

            UPDATE products 
            SET subcategoryid = @class_id 
            WHERE ccode = @title_code 
                AND spdisplaytype = 'Table'

            UPDATE products
            SET subcategoryid = @class_id
            WHERE highercatalogid IN (
                SELECT catalogid FROM products (nolock)
                WHERE ccode = @title_code AND spdisplaytype = 'Table')

            FETCH title_class INTO @title_code
        END

CLOSE title_class

DEALLOCATE title_class

tmp_business_class_titles 如下所示:

class_id,title_code,Default_flag

7,101WGA,0

7,10315,0

29,8600,0

默认标志始终可以为 0,但如果为 1,则逻辑应自动选择该 title_id 的默认 class_id。

因此,当前逻辑在游标中循环遍历上表,然后为每个标题选择前 1 个类 id,按默认标志排序(因此应始终首先返回 default_flag 为 1 的 class_id。)并应用默认值class_id 添加到产品表中。

这段代码大约需要 1 分 20 秒才能运行,我试图将其转换为一两个更新语句,但这样做已经耗尽了我的大脑。

如果这可能的话,任何 TSQL 大师都有任何想法,或者我应该重新评估默认标志如何工作的整个逻辑吗?

为任何帮助干杯。

Basically I have this cursor that was not written by me but is taking some time to process and I was wanting to try and improve it by getting rid of the cursor all together.

Here is the code:

DECLARE @class_id int, @title_code varchar(30)

DECLARE title_class CURSOR FOR
SELECT DISTINCT title_code FROM tmp_business_class_titles (NOLOCK)

OPEN title_class

    FETCH title_class INTO @title_code

    WHILE @@FETCH_STATUS = 0
        BEGIN
            SELECT TOP 1 @class_id = bc1.categoryid
            FROM tmp_business_class_titles bct, 
            dbo.Categories bc1 (nolock) 
            join dbo.Categories bc2 (nolock) on bc2.categoryid = bc1.highercategoryid
            join dbo.Categories bc3 (nolock) on bc3.categoryid = bc2.highercategoryid 
            WHERE bc1.categoryid = bct.class_id
                AND title_code = @title_code
            ORDER BY Default_Flag DESC

            UPDATE products 
            SET subcategoryid = @class_id 
            WHERE ccode = @title_code 
                AND spdisplaytype = 'Table'

            UPDATE products
            SET subcategoryid = @class_id
            WHERE highercatalogid IN (
                SELECT catalogid FROM products (nolock)
                WHERE ccode = @title_code AND spdisplaytype = 'Table')

            FETCH title_class INTO @title_code
        END

CLOSE title_class

DEALLOCATE title_class

The table tmp_business_class_titles looks like this:

class_id,title_code,Default_flag

7,101WGA,0

7,10315,0

29,8600,0

The default flag can always be 0 but if it is 1 then the logic should automatically pick the default class_id for that title_id.

So the current logic loops through the above table in a cursor and then selects the top 1 class id for each title, ordered by the the default flag (so the class_id with a default_flag of 1 should always be returned first.) and applies the default class_id to the products table.

This code takes around 1:20 to run and I am trying to convert this into one or 2 update statements but I have exhausted my brain in doing so.

Any TSQL Guru's have any ideas if this is possible or should I re-evaluate the entire logic on how the default flag works?

cheers for any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我不咬妳我踢妳 2024-10-08 02:13:42

我没有足够的信息可供使用,因此以下查询可能会失败。我特别需要有关产品表的更多信息才能完成这项工作,但假设您有 SQL Server 2005 或更高版本,这可能足以让您朝着正确的方向开始。它使用公共表表达式以及 RANK 函数。我强烈建议学习它们,并且十有八九会大大提高查询的效率。

;WITH cteTitle As (
    SELECT 
        sequence = RANK() OVER (PARTITION BY bct.title_code ORDER BY Default_Flag desc)
        ,bct.title_code
        ,bc1.categoryid
    FROM
        tmp_business_class_titles bct
        join Categories bc1 ON bc1.categoryid = bct.class_id
        join Categories bc2 ON bc2.categoryid = bc1.highercategoryid
        join Categories bc3 ON bc3.categoryid = bc2.highercategoryid
 )                            
 UPDATE 
     prod
 SET
     subcategoryid = ISNULL(t.categoryid,t2.categoryid)
 FROM
     products prod
     LEFT join products subprod ON subprod.catalogid = prod.highercatalogid
     LEFT join cteTitle t ON prod.ccode = t.title_code AND t.sequence = 1 AND prod.spdisplaytype = 'Table'
     LEFT join cteTitle t2 ON subprod.ccode = t2.title_code And t2.sequence = 1 AND subprod.spdisplaytype = 'Table'
 WHERE
     t2.categoryid IS NOT NULL

I don't have quite enough information to work with, so the following query is likely to fail. I particularly need more information on the products table to make this work, but assuming that you have SQL Server 2005 or higher, this might be enough to get you started in the right direction. It utilizes common table expressions along with the RANK function. I highly recommend learning about them, and in all likelihood, it will greatly improve the efficiency of the query.

;WITH cteTitle As (
    SELECT 
        sequence = RANK() OVER (PARTITION BY bct.title_code ORDER BY Default_Flag desc)
        ,bct.title_code
        ,bc1.categoryid
    FROM
        tmp_business_class_titles bct
        join Categories bc1 ON bc1.categoryid = bct.class_id
        join Categories bc2 ON bc2.categoryid = bc1.highercategoryid
        join Categories bc3 ON bc3.categoryid = bc2.highercategoryid
 )                            
 UPDATE 
     prod
 SET
     subcategoryid = ISNULL(t.categoryid,t2.categoryid)
 FROM
     products prod
     LEFT join products subprod ON subprod.catalogid = prod.highercatalogid
     LEFT join cteTitle t ON prod.ccode = t.title_code AND t.sequence = 1 AND prod.spdisplaytype = 'Table'
     LEFT join cteTitle t2 ON subprod.ccode = t2.title_code And t2.sequence = 1 AND subprod.spdisplaytype = 'Table'
 WHERE
     t2.categoryid IS NOT NULL
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文