【问题标题】:Convert CURSOR into SELECT - Send parent table value to joined table returning function as a parameter将 CURSOR 转换为 SELECT - 将父表值作为参数发送到连接表返回函数
【发布时间】:2021-09-28 13:28:24
【问题描述】:

目前这个游标需要很多次才能执行。而且我相信最好的解决方案是将光标转换为SELECT 语句。我已经实现了一些选择语句,但无法将父表的值作为参数发送到第二个表返回函数。您知道如何使用SELECT 语句获得完全相同的结果吗?

这是最初的 CURSOR 实现

declare @orgusers table (UserID int, PRIMARY KEY (UserID))
                delete from @orgusers
                declare curOrgs CURSOR FAST_FORWARD FOR
                    select distinct ('~' + qlu.MemberValue + '~') as curOrgs                    
                    FROM [gl].VTN_QualificationMemberLU qlu 
                    where qlu.MemberType = 45 and qlu.QualificationID = 1111
                open curOrgs
                FETCH NEXT FROM curOrgs INTO @org
                while @@FETCH_STATUS = 0
                begin
                    insert into @orgusers(UserID) 
                    SELECT distinct u.UserID
                    FROM [gl].[GetStudentsByOUPath_BeforeCutoff](@nCompanyid, @org, @dCutOffDate) as u
                    left join @orgusers ou on ou.UserID = u.UserID
                    where ou.UserID is null
                    fetch next from curOrgs INTO @org
                end 
                close curOrgs
                deallocate curOrgs  

我正在寻找一种方法,如何将 CURSOR 转换为 SELECT 语句以在 @orgusers TABLE 中获得相同的 IDs

要重现的场景。

qlu.MemberValue 从名为 VTN_QualificationMemberLU 的表中返回数据,例如 - 2343-2987-2783-2873

因此,基于名为 GetStudentsByOUPath_BeforeCutoff 的 MemberValue 函数返回一个基于某些逻辑的表,其中包含类似 2343 2783 2873

我们将这个 Ids 放入@orgUsers 表中并作为函数的结果返回。

所以根据要求 - VTN_QualificationMemberLU 表有 10 个数据。我们需要使用函数过滤返回 30 个 ID 叫GetStudentsByOUPath_BeforeCutoff。对于VTN_Qual.... 的每一行,我们需要返回 3 个 Id 作为表格结果。

这是要重现的测试脚本。

CREATE TABLE VTN_QualificationMemberLU (
    MemberValue  nvarchar(max) NOT NULL
)


INSERT INTO VTN_QualificationMemberLU (MemberValue) VALUES 
('2385-3772-3764-2918'),
('2385-3772-3764-2918'),
('2382-1237-1203-2367'),
('2123-1238-8123-1232'),
('1238-1222-9982-7129'),
('2385-3772-3764-2918'),
('5645-1232-1203-1232'),
('6675-1238-5655-1232'),
('1238-1233-1232-1231')



CREATE FUNCTION GetStudentsByOUPath_BeforeCutoff  (
    @userIds NVARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN 
    SELECT value  
    FROM STRING_SPLIT(@userIds, '-')  
    WHERE RTRIM(value) <> '';

所以对于VTN_Quali...表的每一行我们需要调用函数并且需要收集函数的表结果。

提前谢谢大家。

【问题讨论】:

  • 请提供重现场景所需的信息,即创建相关表和插入一些示例数据的查询。另外请根据样本数据描述expected结果集
  • @RonenAriely 我只是试图解释这个场景来重现
  • 更少的解释(故事)和更多的代码,我们可以执行以便在几秒钟内重现场景 - 将更适合,让我们浪费更少的时间并提供更快的解决方案,同时帮助其他人同时。请提供完整的演示场景,我们可以代替(或另外)执行来描述表格。我们需要查询来创建相关表并插入一些示例数据作为起点。就个人而言,如果没有这些信息,我通常什至不会阅读整个问题。
  • @RonenAriely 现在我已经调整并添加了一些测试脚本,您可以使用它们来重现问题。我已经在最后一句话中解释了这个问题。谢谢。
  • 这是使用CROSS APPLY 完成的。例如,使用您可以执行的示例表和数据:SELECT * from VTN_QualificationMemberLU CROSS APPLY GetStudentsByOUPath_BeforeCutoff (MemberValue)

标签: sql-server tsql database-cursor


【解决方案1】:

这是要重现的测试脚本。

我忽略了之前的描述,因为我们没有使用 DDL+DML 来重现完整的场景,所以让我们专注于您的示例表和数据

-- DDL+DML
CREATE TABLE VTN_QualificationMemberLU (
    MemberValue  nvarchar(max) NOT NULL
)
GO

INSERT INTO VTN_QualificationMemberLU (MemberValue) VALUES 
('2385-3772-3764-2918'),
('2385-3772-3764-2918'),
('2382-1237-1203-2367'),
('2123-1238-8123-1232'),
('1238-1222-9982-7129'),
('2385-3772-3764-2918'),
('5645-1232-1203-1232'),
('6675-1238-5655-1232'),
('1238-1233-1232-1231')
GO

CREATE FUNCTION GetStudentsByOUPath_BeforeCutoff  (
    @userIds NVARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN 
    SELECT value  
    FROM STRING_SPLIT(@userIds, '-')  
    WHERE RTRIM(value) <> '';
GO

为了对现有表中的所有行执行表的功能,我们可以使用CROSS APPLY

例如:

SELECT t1.MemberValue,t2.[value]
from VTN_QualificationMemberLU t1
CROSS APPLY GetStudentsByOUPath_BeforeCutoff (MemberValue) as t2

显然,如果您只需要函数中的干净值,那么您可以只返回列t2.[value]

【讨论】:

    【解决方案2】:

    好吧,我真的不可能对此进行测试,因为您的问题代码与示例代码和数据之间存在很多差异(缺少变量、列等),但它可能应该是这样的。我刚刚就地注释掉了游标代码,以便您更好地了解如何将代码从游标转换为基于集合:

    declare @orgusers table (UserID int, PRIMARY KEY (UserID))
    delete from @orgusers
    
    --declare curOrgs CURSOR FAST_FORWARD FOR
    ;WITH cte AS
    (   select distinct ('~' + qlu.MemberValue + '~') as curOrgs                    
        FROM [gl].VTN_QualificationMemberLU qlu 
        where qlu.MemberType = 45 and qlu.QualificationID = 1111
    )
    --open curOrgs
    --FETCH NEXT FROM curOrgs INTO @org
    --while @@FETCH_STATUS = 0
    --begin
        insert into @orgusers(UserID) 
        SELECT distinct u.UserID
        FROM cte AS c
        CROSS APPLY [gl].[GetStudentsByOUPath_BeforeCutoff](@nCompanyid, c.curOrgs, @dCutOffDate) as u
        left join @orgusers ou on ou.UserID = u.UserID
        --where ou.UserID is null
        --fetch next from curOrgs INTO @org
    --end 
    --close curOrgs
    --deallocate curOrgs  
    

    我认为您可能可以摆脱 CTE 中的 distinct(您不应该需要两个 DISTINCT,而后一个可以同时完成两者的工作)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-07
      • 2021-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多