3

Could you explain me the strange behaviour?

DECLARE @t VARCHAR(256) = ''

SELECT @t = @t + CAST(smb.symbol AS VARCHAR(256))
FROM (
    SELECT 1,'7'
    UNION ALL
    SELECT 2,'8'
    UNION all
    SELECT 3,'9'
) AS smb(n, symbol)
ORDER BY n

SELECT @t

Outputs:

789

Thats OK for me.

DECLARE @t VARCHAR(256) = ''

SELECT @t = @t + CAST(smb.symbol AS VARCHAR(256))
FROM (
    SELECT NUMS.N-1 AS N, CHAR(N-1) AS symbol
    FROM (
        SELECT 1 + n.n1 + nn.n2 * 10 + nnn.n3 * 100 as N
        FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS n(n1)
            CROSS JOIN (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS nn(n2)
            CROSS JOIN (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS nnn(n3)
    ) AS NUMS
    WHERE NUMS.N BETWEEN 56 AND 58
) AS smb(N, symbol)
ORDER BY smb.N

SELECT @t

Outputs:

9

So why does the second example outputs the last symbol only?

Martin Smith
  • 438,706
  • 87
  • 741
  • 845
John Wales
  • 1,265
  • 2
  • 14
  • 20
  • 4
    You are relying on undocumented and unguaranteed behaviour. This approach to concatenation doesn't always work. Possible duplicate of [nvarchar concatenation / index / nvarchar(max) inexplicable behavior](http://stackoverflow.com/questions/15138593/nvarchar-concatenation-index-nvarcharmax-inexplicable-behavior) – Martin Smith May 13 '13 at 10:32
  • Want to see something funny? Remove ORDER BY from your second query and it'll return 789 as well :). +1 for executable question. – AdamL May 13 '13 at 10:43
  • You should use FOR XML PATH('') – Serge May 13 '13 at 12:14
  • Thanks to everybody! The best practice for me is to avoid undocumented behaviours. – John Wales May 17 '13 at 11:32

1 Answers1

4

Don't rely on order by when using mutlirows variable assignment.

try this for instance:

DECLARE @c INT = 0

SELECT
 @c = @c + x
FROM (VALUES(1),(2),(3)) AS src(x)
WHERE x BETWEEN 1 AND 3 
ORDER BY 1 - x DESC

SELECT @c

SET @c = 0

SELECT
 @c = @c + x
FROM (VALUES(1),(2),(3)) AS src(x)
WHERE x BETWEEN 1 AND 3 
ORDER BY x DESC

SELECT @c

http://sqlmag.com/sql-server/multi-row-variable-assignment-and-order

Serge
  • 6,554
  • 5
  • 30
  • 56
  • 2
    [It still isn't guaranteed even in the absence of `ORDER BY`.](https://connect.microsoft.com/SQLServer/feedback/details/606786/concatenation-into-a-scalar-variable-using-linked-server-in-from-clause-fails-when-casting-or-converting-data). `Even without ORDER BY, we do not guarantee that @var = @var + will produce the concatenated value for any statement that affects multiple rows.` The only reliable method is to use a completely different approach. – Martin Smith May 13 '13 at 12:26