sql >> Database >  >> RDS >> Sqlserver

nvarchar aaneenschakeling / index / nvarchar (max) onverklaarbaar gedrag

TLDR; Dit is geen gedocumenteerde/ondersteunde benadering voor het aaneenschakelen van tekenreeksen over rijen. Het werkt soms maar mislukt soms ook omdat het afhangt van welk uitvoeringsplan je krijgt.

Gebruik in plaats daarvan een van de volgende gegarandeerde benaderingen

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)') 

Achtergrond

Het KB-artikel dat al door VanDerNorth is gelinkt, bevat de regel

Het juiste gedrag voor een samengevoegde aaneenschakelingsquery is niet gedefinieerd.

maar vertroebelt vervolgens het water een beetje door een tijdelijke oplossing te bieden die erop lijkt te wijzen dat deterministisch gedrag mogelijk is.

Om de verwachte resultaten van een samengevoegde aaneenschakelingsquery te verkrijgen, past u een Transact-SQL-functie of -expressie toe op de kolommen in de SELECT-lijst in plaats van in de ORDER BY-component.

Uw problematische zoekopdracht past geen uitdrukkingen toe op kolommen in de ORDER BY clausule.

In het artikel Ordering Guarantees in SQL Server... uit 2005 staat wel

Om redenen van achterwaartse compatibiliteit biedt SQL Server ondersteuning voor toewijzingen van het type SELECT @p =@p + 1 ... ORDER BY bovenaan.

In de plannen waar de aaneenschakeling werkt zoals u verwachtte, de compute scalair met de uitdrukking [Expr1003] = Scalar Operator([@x]+[Expr1004]) verschijnt boven de sortering.

In het plan waar het niet werkt, verschijnt de compute scalaire onder de sort. Zoals uitgelegd in dit connect item uit 2006 wanneer de uitdrukking @x = @x + [msg] verschijnt onder de sortering die voor elke rij wordt geëvalueerd, maar alle evaluaties eindigen met de pre-toewijzingswaarde van @x . In een ander vergelijkbaar Connect-item uit 2006 sprak de reactie van Microsoft over het "oplossen" van het probleem.

In het Microsoft-antwoord op alle latere Connect-items over dit probleem (en er zijn er veel) staat dat dit gewoon niet gegarandeerd is

Voorbeeld 1

we geven geen garanties over de juistheid van aaneenschakelingsquery's (zoals het gebruik van variabele toewijzingen met het ophalen van gegevens in een specifieke volgorde). De uitvoer van de query kan in SQL Server 2008 veranderen, afhankelijk van de plankeuze, gegevens in de tabellen, enz. U moet er niet op vertrouwen dat dit consistent werkt, ook al kunt u met de syntaxis een SELECT-instructie schrijven die het ophalen van geordende rijen combineert met variabele toewijzing.

Voorbeeld 2

Het gedrag dat u ziet, is inherent aan het ontwerp. Het gebruik van toewijzingsbewerkingen (aaneenschakeling in dit voorbeeld) in query's met de ORDER BY-clausule heeft een ongedefinieerd gedrag. Dit kan van release tot release veranderen of zelfs binnen een bepaalde serverversie als gevolg van wijzigingen in het queryplan. U kunt niet op dit gedrag vertrouwen, zelfs als er tijdelijke oplossingen zijn. Zie het onderstaande KB-artikel voor meer details:
http://support.microsoft.com/kb/287515 De ENIGE gegarandeerde mechanismen zijn de volgende:

  1. Gebruik de cursor om in een specifieke volgorde door de rijen te bladeren en de waarden samen te voegen
  2. Gebruik voor xml-query met ORDER BY om de aaneengeschakelde waarden te genereren
  3. Gebruik CLR-aggregaat (dit werkt niet met de ORDER BY-clausule)

Voorbeeld 3

Het gedrag dat u ziet, is eigenlijk ontworpen. Dit heeft te maken met het feit dat SQL een set-manipulatietaal is. Het is niet gegarandeerd dat alle expressies in de SELECTlist (en dit geldt ook voor toewijzingen) precies één keer worden uitgevoerd voor elke uitvoerrij. In feite doet SQL queryoptimizer er alles aan om ze zo min mogelijk uit te voeren. Dit geeft verwachte resultaten wanneer u de waarde van de variabele berekent op basis van enkele gegevens in de tabellen, maar wanneer de waarde die u toewijst afhangt van de vorige waarde van dezelfde variabele, kunnen de resultaten nogal onverwacht zijn. Als de query-optimizer de expressie naar een andere plaats in de zoekstructuur verplaatst, wordt deze mogelijk minder keer geëvalueerd (of slechts één keer, zoals in een van uw voorbeelden). Daarom raden we af om de toewijzingen van het type "iteratie" te gebruiken om aggregatiewaarden te berekenen. We vinden dat op XML gebaseerde tijdelijke oplossingen ... meestal goed werken voor de klanten

Voorbeeld 4

Zelfs zonder ORDER BY kunnen we niet garanderen dat @var =@var + de aaneengeschakelde waarde produceert voor een instructie die van invloed is op meerdere rijen. De rechterkant van de expressie kan één of meerdere keren worden geëvalueerd tijdens het uitvoeren van de query en het gedrag is, zoals ik al zei, afhankelijk van het plan.

Voorbeeld 5

De variabele toewijzing met de SELECT-instructie is een eigen syntaxis (alleen T-SQL) waarbij het gedrag ongedefinieerd of planafhankelijk is als er meerdere rijen worden geproduceerd. Als u de string-aaneenschakeling moet doen, gebruik dan een SQLCLR-aggregaat of FOR XML-query-gebaseerde aaneenschakeling of andere relationele methoden.



  1. Leesbare code schrijven voor VBA - Probeer* patroon

  2. MySQL Buitenlandse sleutel toevoegen

  3. Een databasemodel ontwerpen voor een bioscoopreserveringssysteem

  4. Een tabel neerzetten in SQL