1

This has been killing me all day =D. Please help!

Scenario 1: Two DB's on the same server (A, B) and A has three tables. Query is executed from B.

Scenario 2: Two DB's one server is linked to the other. (B has link A) and A has three tables. Query is executed from B.

In scenario 1 (non linked server):

SET @val = ''
SELECT @val = @val + 'Hello, my name is ' + [name] + '!' + CHAR(10) + CHAR(13)
FROM A.sys.tables

Returns: Hello, my name is Table1! Hello, my name is Table2! Hello, my name is Table3!

In scenario 2 (linked server):

SET @val = ''
SELECT @val = @val + 'Hello, my name is ' + [name] + '!' + CHAR(10) + CHAR(13)
FROM LINKED.A.sys.tables

Returns: Hello, my name is Table3!

Why are these different? If I use openquery() on the linked server the results are the same as scenario 1. I'm trying to avoid using openquery() if possible. Thanks!

decompiled
  • 1,853
  • 3
  • 14
  • 19
  • can u run and tell how many rows returning from this query EXEC ('SELECT name FROM [A].sys.tables') AT [LINKED] – Kumar_2002 Oct 22 '12 at 21:10

1 Answers1

4

Unfortunately, this is an unreliable method of string concatenation in SQL Server. I would avoid it in all but the most trivial of cases. There is some more information in this KB: Execution Plan and Results of Aggregate Concatenation Queries Depend Upon Expression Location.

That said, I was able to both duplicate your problem and provide a workaround in my environment:

SET @val = ''
SELECT @val = @val + 'Hello, my name is ' + replace([name], '', '') + '!' + CHAR(10) + CHAR(13)
FROM LINKED.A.sys.tables

Notice that I've added an empty replace function to the expression. Though it should do nothing to the output, it does add a local "compute scalar" step to the query plan. This seems to pull back all of the data from the name column to then be processed locally rather than just letting the remote query return what it thinks is needed.

I'm not sure if there's a better function to use other than a replace with empty arguments. Perhaps a double reverse or something. Just be sure to cast to a max datatype if necessary as the documentation states.

UPDATE

Simply declaring @var as varchar(max) rather than nvarchar(max) clears up the problem, as it then brings back the entire name column (type sysname -- or nvarchar(128) -- I believe) for local processing just like the replace function did. I cannot pretend to know which combination of linked server settings and implicit casting causes this to come up. Hopefully someone with more knowledge in this area can chime-in!

Tim Lehner
  • 14,813
  • 4
  • 59
  • 76
  • 1
    I'd be curious what settings you have for your linked server. I was unable to reproduce the issue. – Aaron Bertrand Oct 22 '12 at 21:21
  • @AaronBertrand, interestingly, I can't come up with a [configuration of the linked server](http://msdn.microsoft.com/en-us/library/ms178532.aspx) the doesn't reproduce the issue, though it was only a few minutes of fiddling. – Tim Lehner Oct 22 '12 at 21:48
  • 1
    @AaronBertrand, simply declaring `@var` as `varchar(max)` clears up the problem (I had tested with nvarchar). Which did you use? – Tim Lehner Oct 22 '12 at 21:56
  • The only modifications I made to the linked server query in the question above was server name & database name. – Aaron Bertrand Oct 22 '12 at 22:04