T-SQL 相当于 Oracle 的收集方法(第一个、最后一个、下一个)?

Posted

技术标签:

【中文标题】T-SQL 相当于 Oracle 的收集方法(第一个、最后一个、下一个)?【英文标题】:T-SQL equivalent of Oracle's collection methods (first, last, next)? 【发布时间】:2013-03-04 17:17:30 【问题描述】:

我们正在从 Oracle 迁移到 SQL Server,并且我正在从填充了 BULK COLLECT INTO 查询的表变量转换查询。我正在考虑使用游标(绝对可以接受其他建议),但在处理查询的 Oracle 代码中,它使用的是Table_var.FIRST.NEXT.LAST。这是一些关于如何使用这些的示例代码。似乎第一个/下一个/最后一个正在为表 var 的记录提供索引。

TYPE Pers_DOB_LastInitial IS RECORD (
  Person_ID Person.Person_ID%TYPE,
  DOB Person.Birthdate%TYPE,
  LastInitial VARCHAR2(1)
);

TYPE Dup_Table IS TABLE OF Pers_DOB_LastInitial INDEX BY BINARY_INTEGER;

Dup_Tab Dup_Table;

以及使用这些类型的函数:

FUNCTION Last_In_Group( pStart NUMBER, pDOB Person.Birthdate%TYPE, pLastInitial VARCHAR2 )
     RETURN NUMBER IS
  vResult NUMBER;
BEGIN
  IF pStart = Dup_Tab.LAST THEN
     RETURN pStart;
  END IF;

  vResult := pStart;

  FOR vIndex IN pStart .. Dup_Tab.LAST LOOP
     IF Dup_Tab.EXISTS( vIndex ) THEN
        IF Dup_Tab( vIndex ).DOB = pDOB AND Dup_Tab( vIndex ).LastInitial = pLastInitial THEN
           vResult := vIndex;
        ELSE
           EXIT;
        END IF;
     END IF;
  END LOOP;

  RETURN vResult;
END Last_In_Group;

我不需要为我完成编码,只需要指出正确的方向。我正在考虑使用游标,但我唯一熟悉的只是从 T-SQL 中的游标中获取下一条记录,并想看看是否有等效的方法来引用游标(或临时表)的行索引)。


编辑:我刚刚发现了以下内容并正在研究它。绝对愿意提供有关这是否是一条好路径或者游标是否仍然更好的提示。

http://www.sql-server-performance.com/2004/operations-no-cursors/2/

DECLARE @dupTab TABLE (
    person_id numeric(8,0),
    DOB date,
    LastInitial char(1)
)

INSERT @dupTab
SELECT ...

【问题讨论】:

【参考方案1】:

不是 100% 确定您在问什么,但您是否查看过 Sql Server 2012 中的新 LEAD、LAG、FIRST_VALUE 和 LAST_VALUE 关键字?

【讨论】:

不,那是完全不同的东西。 我已经更新了这个问题(希望)让它更清楚我在问什么,并提供更好的示例代码。【参考方案2】:

假设您的表名为 Dup_Tab,@DOB 和 @LastInitial 是您传递给函数的变量,这可能有效吗?

select PersonID from(
select
 rank = row_number() over (order by DOB DESC, LastInitial DESC),
 PersonID
from dup_tab where DOB=@DOB and LastInitial=@LastInitial
) subgroup 
where rank=1

它只是使用窗口化的 Rank() 函数根据 DOB/LastInitial 最后排序的顺序为每条记录分配一个行号,然后选择 rank = 1 的行,为您提供一组人中的最后一条记录特定的 DOB 和 LastInitial。

【讨论】:

【参考方案3】:

我将您的示例代码翻译成与 SQL-Server 对应的代码。如果您想逐行处理,最好的执行方式是 imo 使用 FAST_FORWARD 游标。

代码:

    IF  EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[Last_In_Group]') AND xtype in (N'FN', N'IF', N'TF'))
        drop function  Last_In_Group
    go

    create function Last_In_Group(@pStart  int, @pDOB date, @pLastInitial varchar(1))
    returns int
    AS
    BEGIN
        DECLARE @Dup_Tab TABLE(
            Person_ID int,
            DOB date,
            LastInitial varchar(1)
        )
        -- populate the table with some data
        insert @Dup_Tab values
        (1, '31.12.2013', 'P'), (2, '24.12.2013', 'C'), (3, '24.12.2013', 'C')

        declare @vResult int = 0,
                @cDOB date,
                @cLastInitial varchar(1)

        if(@vResult = @pStart) return @pStart
        set @vResult = @pStart

        -- loop over your data with a fast cursor
        declare cur cursor FAST_FORWARD for select DOB, LastInitial from @Dup_Tab
        open cur
        fetch next from cur
        into @cDOB, @cLastInitial

        while @@FETCH_STATUS = 0
        begin
            if(@cDOB = @pDOB and @cLastInitial = @pLastInitial)
                set @vResult += 1
            fetch next from cur
            into @cDOB, @cLastInitial
        end

        return @vResult;
    end
    go

    print dbo.Last_In_Group(1, '24.12.2013', 'C')
    go

它可能无法作为您上面的示例,但我希望这可以为您提供一些进一步的提示。

【讨论】:

以上是关于T-SQL 相当于 Oracle 的收集方法(第一个、最后一个、下一个)?的主要内容,如果未能解决你的问题,请参考以下文章

sql 高级T-SQL脚本(从这里和他们收集)

T-SQL:GO语句和批处理(更新ing)

T-SQL

Oracle 存储过程

如何在T-sql中实现相当于“短路求值”

Microsoft T-SQL 到 Oracle SQL 的翻译