sql >> Databasteknik >  >> RDS >> Sqlserver

nvarchar-konkatenering / index / nvarchar(max) oförklarligt beteende

TLDR; Detta är inte en dokumenterad/stödd metod för att sammanfoga strängar över rader. Det fungerar ibland men misslyckas också ibland eftersom det beror på vilken genomförandeplan du får.

Använd istället någon av följande garanterade metoder

SQL Server 2017+

SELECT @a = STRING_AGG([msg], '') WITHIN GROUP (ORDER BY [priority] ASC)
FROM bla
where   autofix = 0

SQL Server 2005+

SELECT @a = (SELECT [msg] + ''
             FROM   bla
             WHERE  autofix = 0
             ORDER  BY [priority] ASC
             FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)') 

Bakgrund

KB-artikeln som redan länkats av VanDerNorth innehåller raden

Det korrekta beteendet för en aggregerad sammanlänkningsfråga är odefinierat.

men fortsätter sedan med att lera lite i vattnet genom att tillhandahålla en lösning som verkar indikera att deterministiskt beteende är möjligt.

För att uppnå de förväntade resultaten från en aggregerad konkateneringsfråga, applicera vilken Transact-SQL-funktion eller ett uttryck som helst på kolumnerna i SELECT-listan istället för i ORDER BY-satsen.

Din problematiska fråga tillämpar inga uttryck på kolumner i ORDER BY klausul.

2005 års artikel Ordergarantier i SQL Server... står det

Av bakåtkompatibilitetsskäl tillhandahåller SQL Server stöd för tilldelningar av typen SELECT @p =@p + 1 ... ORDER BY längst upp.

I planerna där sammankopplingen fungerar som du förväntade dig, beräknar skalären med uttrycket [Expr1003] = Scalar Operator([@x]+[Expr1004]) visas ovanför sorteringen.

I planen där den inte fungerar visas beräkningsskalären under sorteringen. Som förklaras i detta kopplingsobjekt från 2006 när uttrycket @x = @x + [msg] visas under sorteringen den utvärderas för varje rad men alla utvärderingar slutar med att använda pre-tilldelningsvärdet @x . I ett annat liknande Connect Item från 2006 talade svaret från Microsoft om att "fixa" problemet.

Microsofts svar på alla senare Connect-objekt i denna fråga (och det finns många) säger att detta helt enkelt inte är garanterat

Exempel 1

vi ger inga garantier för korrektheten av sammankopplingsfrågor (som att använda variabeltilldelningar med datahämtning i en specifik ordning). Frågeutdata kan ändras i SQL Server 2008 beroende på planval, data i tabellerna etc. Du bör inte lita på att detta fungerar konsekvent även om syntaxen låter dig skriva en SELECT-sats som blandar ordnade radhämtning med variabel tilldelning.

Exempel 2

Beteendet du ser är av design. Att använda tilldelningsoperationer (sammankoppling i det här exemplet) i frågor med ORDER BY-satsen har ett odefinierat beteende. Detta kan ändras från utgåva till utgåva eller till och med inom en viss serverversion på grund av ändringar i frågeplanen. Du kan inte lita på detta beteende även om det finns lösningar. Se KB-artikeln nedan för mer information:
http://support.microsoft.com/kb/287515 Den ENDA garanterade mekanismen är följande:

  1. Använd markören för att gå igenom raderna i specifik ordning och sammanfoga värdena
  2. Använd för xml-fråga med ORDER BY för att generera de sammanlänkade värdena
  3. Använd CLR-aggregat (detta fungerar inte med ORDER BY-klausul)

Exempel 3

Beteendet du ser är faktiskt av design. Detta har att göra med att SQL är ett set-manipulationsspråk. Alla uttryck i SELECT-listan (och detta inkluderar också tilldelningar) är inte garanterade att exekveras exakt en gång för varje utdatarad. Faktum är att SQL queryoptimizer försöker köra dem så få gånger som möjligt. Detta kommer att ge förväntade resultat när du beräknar värdet på variabeln baserat på vissa data i tabellerna, men när värdet som du tilldelar beror på det tidigare värdet av samma variabel, kan resultatet bli ganska oväntat. Om frågeoptimeraren flyttar uttrycket till en annan plats i frågeträdet, kan det utvärderas färre gånger (eller bara en gång, som i ett av dina exempel). Det är därför vi inte rekommenderar att du använder tilldelningar av typen "iteration" för att beräkna aggregerade värden. Vi finner att XML-baserade lösningar ... vanligtvis fungerar bra för kunderna

Exempel 4

Även utan ORDER BY garanterar vi inte att @var =@var +kommer att producera det sammanlänkade värdet för något påstående som påverkar flera rader. Den högra sidan av uttrycket kan utvärderas antingen en eller flera gånger under exekveringen av en fråga och beteendet som jag sa är planberoende.

Exempel 5

Variabeltilldelningen med SELECT-satsen är en egen syntax (endast T-SQL) där beteendet är odefinierat eller planberoende om flera rader produceras. Om du behöver göra strängsammansättningen använder du en SQLCLR-aggregation eller FOR XML-frågebaserad sammanlänkning eller andra relationsmetoder.



  1. PostgreSQL:FEL:42601:en kolumndefinitionslista krävs för funktioner som returnerar post

  2. Jämför Oracle RAC HA-lösning med Galera Cluster för MySQL eller MariaDB

  3. Hämta data från lagrad procedur som har flera resultatuppsättningar

  4. Förstå PIVOT-funktionen i T-SQL