2017-04-10 187 views
2

我有一个存储过程,它选择一些1-n关系和相关数据作为XML数据引用列。SQL Server查询性能:嵌套游标

其目的是将一条记录和1-n关系作为一条记录添加额外的数据列,这是通过将这些相关数据添加为XML来完成的。

参考表:(表一)

ID NAME  VALUE 
--------------------- 
1 Sepehr 1000  
2 Sarah  1001 

相关表(表B)

ID Value FK_Value ORDER TITLE 
------------------------------------- 
1  A  1000   1  t1 
2  B  1000   2  t2 
3  C  1000   3  t3 

我想这样的输出:

ID NAME FK_Value Attribs 
----------------------------------------------------- 
1 Sepehr 1000  <XML><ID>1</ID><ID>2</ID><ID>3</ID></XML> 
2 Sarah  1001  null 

其实我是希望创建一个视图来做到这一点,但我不能和有人告诉我它不可能使用视图。

最后,这是我写的存储过程 - 这是一种正确的方法还是有其他方法?

DECLARE @T1 table (A_ID int,Attribs XML) 

DECLARE db_cursorLegendRowsValues CURSOR FOR 
    SELECT ID, VALUE 
    FROM A 

OPEN db_cursorLegendRowsValues 

FETCH NEXT FROM db_cursorLegendRowsValues INTO @loop_ID, @loop_VALUE 

WHILE @@FETCH_STATUS = 0  
BEGIN 
    DECLARE db_cursorInternal CURSOR FOR 
     SELECT TITLE, ORDER 
     FROM B 
     WHERE FK_Value = @loop_VALUE 

    OPEN db_cursorInternal 

    FETCH NEXT FROM db_cursorInternal INTO @tmpTitle, @ORDER 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @querySelect = @querySelect + ', MAX(CASE WHEN order = ' + cast(@ORDER as nvarchar(max)) + ' THEN value END) AS [' +REPLACE (@tmpTitle,' ','_') + '] ' 

     FETCH NEXT FROM db_cursorInternal INTO @tmpTitle, @ORDER 
    END 

    CLOSE db_cursorInternal 
    DEALLOCATE db_cursorInternal 

    SET @query = 
     ' SELECT ' + cast(@loop_ID as nvarchar(max)) +',(
          SELECT A.Value, 
     ' 
    SET @query = @query + STUFF(@querySelect,1,1,'') + ' FROM A 
     WHERE [A.Value] = ' + cast(@loop_VALUE as nvarchar(max)) + ' 
     FOR XML RAW (''Item''), root (''Items'') , ELEMENTS XSINIL)' 

    SET @querySelect = '' 
    --PRINT(@query) 

    INSERT into @T1 execute (@query) 

    FETCH NEXT FROM db_cursorLegendRowsValues INTO @loop_ID, @loop_VALUE 
END 

CLOSE db_cursorLegendRowsValues 
DEALLOCATE db_cursorLegendRowsValues 

SELECT * FROM @T1 
+0

好得多在这里展示的样本数据和预期的结果 –

+0

难道没有返回预期的效果?如果你在这里只是为了找到有效的方法来做到这一点,那么[代码评论](http://codereview.stackexchange.com/)是这类类型问题的最佳选择。 – mmushtaq

+0

是的,我试图找到有效的方法。 我不知道代码审查,谢谢 –

回答

1

一大堆可以凝结成几行字,没有游标需要在所有。这西港岛线在视图中可用:

DECLARE @tblA TABLE(ID INT IDENTITY,NAME VARCHAR(100),VALUE INT); 
INSERT INTO @tblA VALUES 
('Sepehr',1000)  
,('Sarah',1001); 

DECLARE @tblB TABLE(ID INT IDENTITY,Value VARCHAR(100),FK_Value INT,[ORDER] INT,TITLE VARCHAR(100)); 
INSERT INTO @tblB VALUES 
('A',1000,1,'t1') 
,('B',1000,2,'t2') 
,('C',1000,3,'t3'); 

SELECT a.* 
     ,(SELECT ID FROM @tblB AS b WHERE b.FK_Value=a.VALUE FOR XML PATH(''),ROOT('XML'),TYPE) AS Attribs 
FROM @tblA AS a 

结果

ID NAME VALUE Attribs 
1 Sepehr 1000 <XML><ID>1</ID><ID>2</ID><ID>3</ID></XML> 
2 Sarah 1001 NULL 
+0

这是工作,因为它应该。 这里的问题是我必须从另一个表中获取XML元素的名称。 所以我认为我必须使用动态查询这是不可能的使用视图 –

+1

@SepehrDavarnia请避免变色龙问题...在您的问题中,您提供样本数据和预期的输出。这两个答案提供了一个(非常相似)的解决方案...现在你说,*这里的问题是我必须从另一个表中获取xml元素的名称。* **我不知道你的意思是... ** SO的一个原则是:**一个问题,一个问题**。我会要求您对现有答案进行投票,选择其中一个接受答案作为解决方案,**开始一个新问题**,您将在这里为此新问题提供**更多信息**,样本和预期输出。 Thx – Shnugo

+0

嗨Shnugo。感谢您的建议。我以这种方式问了我的问题,因为我认为答案可能会解决问题。而且我还提供了我自己的查询以显示确切的事情。不管怎样,谢谢你 –

1

有可能只用一个查询来做到这一点 - 你可以使用子查询与您的选择如下:

select id 
    , name 
    , value as fk_value 
    , (select id from @table_b b 
     where a.value = b.fk_value 
     for xml path (''), root ('xml')) 
from @table_a a