T-SQL从行连接字符串

时间:2011-11-14 13:01:34

标签: tsql concatenation

我尝试通过连接另一个表中的行来更新临时表中的列。

看看这个:

DECLARE @Test VARCHAR(MAX);

CREATE TABLE #Test
(
     EmployeeId INT
     ,Html VARCHAR(MAX)
);

CREATE TABLE #EmployeeItems
(
    EmployeeId INT
    ,ItemNo INT
);

INSERT INTO #EmployeeItems (EmployeeId, ItemNo)
VALUES
    (1, 1)
    ,(1, 2);

INSERT INTO #Test (EmployeeId, Html) VALUES (1, '<div class="first">');
SET @Test = '<div class="first">';

UPDATE T SET Html += '<div class="second">' + CAST(E.ItemNo AS VARCHAR) + '</div>'
FROM #Test AS T
    JOIN #EmployeeItems AS E ON T.EmployeeId = E.EmployeeId;

SELECT @Test += '<div class="second">' + CAST(E.ItemNo AS VARCHAR) + '</div>'
FROM #Test AS T
JOIN #EmployeeItems AS E ON T.EmployeeId = E.EmployeeId;

UPDATE #Test SET Html += '</div>';
SET @Test += '</div>';

SELECT Html FROM #Test;
SELECT @Test;

DROP TABLE #Test;
DROP TABLE #EmployeeItems;

#Test表中的列包含:<div class="first"><div class="second">1</div></div>

@Test变量包含:<div class="first"><div class="second">1</div><div class="second">2</div></div>

这是为什么?它有什么区别?我以为我会得到相同的结果,但在表格中它只连接一行,第一行。

如果不运行光标,我应该怎么做才能更新我的表?

修改

我原来的问题来自这样的事情:

我的输入数据是

CREATE TABLE #Actions(EmployeeId INT,EmployeeName VARCHAR(100),ActionStart TIME,ActionEnd TIME,Type VARCHAR(10));
INSERT INTO #Actions(EmployeeId,EmployeeName,ActionStart,ActionEnd, Type)
VALUES (1,'Bob','09:00','12:00', 'action'),(1,'Bob','14:30','16:00', 'action'),(1,'Bob','18:00','20:00', 'event'),(2,'Susan','10:00','12:00', 'action');

我想要这样的输出

<div class="employee" employeeid="1" employeename="Bob">
    <div class="action" start="09:00" end="12:00" type="action"></div>
    <div class="action" start="14:30" end="16:00" type="action"></div>
    <div class="action" start="18:00" end="20:00" type="event"></div>
</div>
<div class="employee" employeeid="2" employeename="Susan">
    <div class="action" start="10:00" end="12:00" type="action"></div>
</div>

与第一个例子一样,这是一个简化的例子。但如果我解决了一个案例,我可以解决我的问题。你会如何使用FOR XML子句做到这一点?

2 个答案:

答案 0 :(得分:0)

对于测试表,更新是针对每一行完成的,因此如果从表中选择所有行,您将获得两行:

<div class="first"><div class="second">1</div></div>
<div class="first"><div class="second">2</div></div>

在第二种情况下,它会添加'<div class="second">' + CAST(E.ItemNo AS VARCHAR) + '</div>'次,因为表中有行。由于你有两行,它会将两个div添加到变量中。

如果希望表的每一行都具有@Test的值,则不需要游标。只需更新表格即可获得@Test

的值

答案 1 :(得分:0)

将变量连接看作是一个怪癖;它是不受支持的行为,在代码中被大量使用:)如果你想继续使用它,你可以像这样修改你的UPDATE语句:

UPDATE t 
SET HTML = @Test
FROM #test t

另一种方法是使用FOR XML语法连接

CREATE TABLE #Test
    (
      EmployeeId INT
    , Html VARCHAR(MAX)
    ) ;
CREATE TABLE #EmployeeItems
    (
      EmployeeId INT
    , ItemNo INT
    ) ;
INSERT  INTO #EmployeeItems
        ( EmployeeId, ItemNo )
VALUES  ( 1, 1 )     ,
        ( 1, 2 ) ;
INSERT  INTO #Test
        ( EmployeeId, Html )
VALUES  ( 1, '<div class="first">' ) ;

UPDATE  #Test
SET     HTML+= REPLACE(REPLACE(( SELECT '|div class="second"|'
                                        + CAST(E.ItemNo AS VARCHAR) + '|/div|'
                                 FROM   #Test AS T
                                        JOIN #EmployeeItems AS E ON T.EmployeeId = E.EmployeeId
                               FOR
                                 XML PATH('')
                               ), '|div class="second"|',
                               '<div class="second">'), '|/div|', '</div>')    
UPDATE  #Test
SET     Html += '</div>' ;

SELECT  Html
FROM    #Test ;


DROP TABLE #Test ;
DROP TABLE #EmployeeItems ;  

或(也许最好),只需直接构建XML文档。

SELECT  'first' AS "div/@class"
      , 'second' AS "div/div/@class"
      , e.ItemNo AS "div/div"
FROM    #EmployeeItems e
FOR     XML PATH('') 

编辑问题的附加答案:

BEGIN TRAN


CREATE TABLE #Actions
    (
      EmployeeId INT
    , EmployeeName VARCHAR(100)
    , ActionStart TIME
    , ActionEnd TIME
    , Type VARCHAR(10)
    ) ;
INSERT  INTO #Actions
        ( EmployeeId, EmployeeName, ActionStart, ActionEnd, Type )
VALUES  ( 1, 'Bob', '09:00', '12:00', 'action' ),
        ( 1, 'Bob', '14:30', '16:00', 'action' ),
        ( 1, 'Bob', '18:00', '20:00', 'event' ),
        ( 2, 'Susan', '10:00', '12:00', 'action' ) ; 

;
WITH    CTE
          AS ( SELECT DISTINCT
                        EmployeeID
                      , EmployeeName
               FROM     #actions
             )
    SELECT  'employee' AS "@class"
          , employeeid AS "@employeeid"
          , employeename AS "@employeename"
          , ( SELECT    'action' AS "@class"
                      , ActionStart AS "@start"
                      , ActionEnd AS "@end"
                      , Type AS "@type"
              FROM      #Actions a2
              WHERE     a2.EmployeeId = a.EmployeeID
            FOR
              XML PATH('div')
                , TYPE
            )
    FROM    cte a
FOR     XML PATH('div') 


ROLLBACK TRAN