需要将一个order by放入使用xml节点的游标声明中

时间:2013-11-27 17:36:34

标签: sql sql-server xml

所以我试图使用游标将一些xml插入到我的SQL数据库中,我想将一个'order by'语句放入游标声明中,否则优化器决定将所有节点按字母顺序排列。

我的光标声明是:

declare cur1 cursor local for

    select
        P.DescriptionId, N.Description
    from (
        select
            T.C.value('.', 'nvarchar(max)') as Description
        from @TheRole.nodes('/descriptions/description') as T(C)


    ) as N
        left outer join PositionsDescriptions as P on  N.Description = P.Description

我试图插入:

order BY P.$IDENTITY

根据要求 - 这是整个SP:

@Title                  nvarchar(50),
@Location               nvarchar(50),
@ShortDescription       nvarchar(max),
@MaximumSalary          nvarchar(max) = null,
@StatusId               int,
@DepartmentId           int,
@SubDepartmentId        int = null,
@TheRole                xml = null,
@Essentials             xml = null,
@Desirable              xml = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE @PositionId as int

--DESCRIPTION TABLES
DECLARE @TableRole TABLE(Description nvarchar(MAX), OrderNumber int)
--DECLARE @TableRole                TABLE(RowID int not null primary key identity(1,1), Description nvarchar(MAX), OrderNumber int)
DECLARE @TableEssentials        TABLE(RowID int not null primary key identity(1,1), Description nvarchar(MAX), OrderNumber int)
DECLARE @TableDesirable         TABLE(RowID int not null primary key identity(1,1), Description nvarchar(MAX), OrderNumber int)
DECLARE @RowsToProcess          int,
@CurrentRow                     int,
@Description                    nvarchar(MAX),
@OrderNumber            int,


--DESCRIPTIONS
@DescriptionId          int
set @OrderNumber = 1

-- POSITIONS

if @SubDepartmentId = 0
    SET @SubDepartmentId = NULL

INSERT INTO Positions (Title, Location, Description, MaximumSalary, StatusId, SubDepartmentId, DepartmentId, Published, LastUpdatedDate)
VALUES (@Title, @Location, @ShortDescription, @MaximumSalary,@StatusId, @SubDepartmentId, @DepartmentId, GETDATE(), GETDATE())

SET @PositionId = scope_identity()

-- POSITIONSDESCRIPTIONS AND POSITIONS_DESCRIPTIONS
-- TheRole

declare cur1 cursor local for

    select
        P.DescriptionId, N.Description
    from (
        select
            T.C.value('.', 'nvarchar(max)') as Description
        from @TheRole.nodes('/descriptions/description') as T(C)


    ) as N
        left outer join PositionsDescriptions as P on  N.Description = P.Description


open cur1
while 1 = 1
begin
    fetch cur1 into @DescriptionId, @Description
    if @@fetch_status <> 0 break

    if @DescriptionId is null
        begin
            insert into PositionsDescriptions (Description)
            select @Description

            select @DescriptionId = scope_identity()

        end

    insert INTO Positions_Descriptions(PositionId, SectionId, DescriptionId, OrderNumber)
    VALUES (@PositionId, 1, @DescriptionId, @OrderNumber)
    set @OrderNumber = @OrderNumber + 1


end
close cur1
deallocate cur1

-- Essentials
declare cur1 cursor local fast_forward for
    select
        P.DescriptionId, N.Description
    from (
        select
            T.C.value('.', 'nvarchar(max)') as Description
        from @Essentials.nodes('/descriptions/description') as T(C)
    ) as N
        left outer join PositionsDescriptions as P on P.Description = N.Description


open cur1
while 1 = 1
begin
    fetch cur1 into @DescriptionId, @Description
    if @@fetch_status <> 0 break

    if @DescriptionId is null
        begin
            insert into PositionsDescriptions (Description)
            select @Description

            select @DescriptionId = scope_identity()

        end

    insert INTO Positions_Descriptions(PositionId, SectionId, DescriptionId, OrderNumber)
    VALUES (@PositionId, 2, @DescriptionId, @OrderNumber)
    set @OrderNumber = @OrderNumber + 1


end
close cur1
deallocate cur1

-- Desirable
declare cur1 cursor local fast_forward for
    select
        P.DescriptionId, N.Description
    from (
        select
            T.C.value('.', 'nvarchar(max)') as Description
        from @Desirable.nodes('/descriptions/description') as T(C)
    ) as N
        left outer join PositionsDescriptions as P on P.Description = N.Description

Declare @DesirablesOrderNumber int = 1
open cur1
while 1 = 1
begin
    fetch cur1 into @DescriptionId, @Description
    if @@fetch_status <> 0 break

    if @DescriptionId is null
        begin
            insert into PositionsDescriptions (Description)
            select @Description

            select @DescriptionId = scope_identity()

        end

    insert INTO Positions_Descriptions(PositionId, SectionId, DescriptionId, OrderNumber)
    VALUES (@PositionId, 3, @DescriptionId, @OrderNumber)
    set @OrderNumber = @OrderNumber + 1

end
close cur1
deallocate cur1

END

如果有比光标更好的方法,我很想知道!这是我正在尝试解决的其他人的代码,我是SQL的新手,所以如果我有点慢,请道歉。

有关详细信息,请参阅上面提到的表格PositionsDescriptions和Positions_Descriptions。

PositionsDescriptions看起来像这样:

DescriptionId Description

1                    test

2                    abc

此数据与名为Positions_Descriptions的表中的作业(或位置)相关,如下所示:

PositionId  SectionId  DescriptionId OrderNumber

1               1               1              1

1               1               2              2

问题在于,如果你有(例如)这样的事情:

@TheRole = "<descriptions><description>test</description><description>abc</description></descriptions>"

然后信息不按该顺序存储。但存储以便描述按字母顺序返回。

换句话说,你得到了这个

PositionId  SectionId  DescriptionId OrderNumber

1               1               2              1

1               1               1              2

而不是这个:

PositionId  SectionId  DescriptionId OrderNumber

1               1               1              1

1               1               2              2

2 个答案:

答案 0 :(得分:1)

如果没有order by子句,您的行可以以优化程序认为合适的任何方式返回。

在您的情况下,这意味着列OrderNumber可能与XML中元素的顺序不匹配。

使用nodes()命令row_number()提取的XML元素有一个技巧。有关详细信息,请参阅Does the nodes() method keep the document order?

使用此游标定义,您的行将按照它们存储在XML中的顺序进行处理。

declare cur1 cursor local for
    select
        P.DescriptionId, N.Description
    from (
        select
            T.C.value('.', 'nvarchar(max)') as Description,
            row_number() over(order by T.C) as rn
        from @TheRole.nodes('/descriptions/description') as T(C)
    ) as N
        left outer join PositionsDescriptions as P on  N.Description = P.Description
    order by N.rn

SQL Fiddle

答案 1 :(得分:1)

Mikael Eriksson已经介绍了订购问题。您可以在不必使用Cusror的情况下插入表(不包括任何重复项)的方法是向INSERT..SELECT添加WHERE EXISTS子句,以过滤掉已存在的那些子句。

像这样:

INSERT INTO PositionsDescriptions( Description )
SELECT  T.C.value('.', 'nvarchar(max)')
FROM    @TheRole.nodes('/descriptions/description') as T(C)
WHERE   NOT EXISTS 
        (
            SELECT * From PositionsDescriptions N
            WHERE T.C.value('.', 'nvarchar(max)') = N.Description
        )

如果您需要防止同一来源中的重复项,您可以将DISTINCT添加到外部SELECT。