TSQL - 不使用游标将一个表映射到另一个表

时间:2011-01-25 19:34:10

标签: tsql

我有以下结构的表格

create table Doc(
    id                  int identity(1, 1) primary key,
    DocumentStartValue  varchar(100)
)
create Metadata (
    DocumentValue       varchar(100),
    StartDesignation    char(1),
    PageNumber          int
)
GO

Doc contains
    id      DocumentStartValue
    1000    ID-1
    1100    ID-5
    2000    ID-8
    3000    ID-9

Metadata contains
    Documentvalue   StartDesignation    PageNumber
    ID-1            D                   0
    ID-2            NULL                1
    ID-3            NULL                2
    ID-4            NULL                3
    ID-5            D                   0
    ID-6            NULL                1
    ID-7            NULL                2
    ID-8            D                   0
    ID-9            D                   0

我需要将Metadata.DocumentValues映射到Doc.id

所以我需要的结果就像是

id      DocumentValue   PageNumber
1000    ID-1            0
1000    ID-2            1
1000    ID-3            2
1000    ID-4            3
1100    ID-5            0
1100    ID-6            1
1100    ID-7            2
2000    ID-8            0
3000    ID-9            0

可以在不使用光标的情况下实现吗?

2 个答案:

答案 0 :(得分:1)

有点像,抱歉无法测试

;WITH RowList AS
(   --assign RowNums to each row...
    SELECT
        ROW_NUMBER() OVER (ORDER BY id) AS RowNum,
        id, DocumentStartValue
    FROM
        doc
), RowPairs AS
(   --this allows us to pair a row with the previous rows to create ranges
    SELECT 
       R.DocumentStartValue AS Start, R.id,
       R1.DocumentStartValue AS End
    FROM
       RowList R JOIN RowList R1 ON R.RowNum + 1 = R1.RowNum
)
--use ranges to join back and get the data
SELECT
    RP.id, M.DocumentValue, M.PageNumber
FROM
    RowPairs RP
    JOIN
    Metadata M ON RP.Start <= M.DocumentValue AND M.DocumentValue < RP.End

编辑:这假设您可以依赖ID-x值匹配和升序。如果是这样,StartDesignation是多余的/冗余的,可能与Doc表DocumentStartValue冲突

答案 1 :(得分:1)


with rm as
(
  select DocumentValue
    ,PageNumber
    ,case when StartDesignation = 'D' then 1 else 0 end as IsStart
    ,row_number() over (order by DocumentValue) as RowNumber
  from Metadata
)
,gm as
(
  select
     DocumentValue as DocumentGroup
    ,DocumentValue
    ,PageNumber
    ,RowNumber
  from rm
  where RowNumber = 1

  union all

  select
     case when rm.IsStart = 1 then rm.DocumentValue else gm.DocumentGroup end
    ,rm.DocumentValue
    ,rm.PageNumber
    ,rm.RowNumber
  from gm
  inner join rm on rm.RowNumber = (gm.RowNumber + 1)
)
select d.id, gm.DocumentValue, gm.PageNumber
from Doc d
inner join gm on d.DocumentStartValue = gm.DocumentGroup

尝试使用上面的查询(也许您还需要添加option (maxrecursion ...))并在DocumentValue上为元数据表添加索引。此外,它是可能的 - 最好在插入Metadat行时保存适当的组。

UPD :我在我的查询中对其进行了测试并修复了错误,并没有起作用,并在初始问题中给出了结果。

UPD2 :推荐索引:


create clustered index IX_Metadata on Metadata (DocumentValue)
create nonclustered index IX_Doc_StartValue on Doc (DocumentStartValue)