sql >> Database teknologi >  >> RDS >> Sqlserver

nvarchar-sammenkædning / indeks / nvarchar(max) uforklarlig adfærd

TLDR; Dette er ikke en dokumenteret/understøttet tilgang til sammenkædning af strenge på tværs af rækker. Det virker nogle gange, men også nogle gange fejler det, da det afhænger af, hvilken eksekveringsplan du får.

Brug i stedet en af ​​følgende garanterede tilgange

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

Baggrund

KB-artiklen, der allerede er linket til af VanDerNorth, inkluderer linjen

Den korrekte adfærd for en samlet sammenkædningsforespørgsel er udefineret.

men fortsætter derefter med at mudre vandet lidt ved at give en løsning, der synes at indikere, at deterministisk adfærd er mulig.

For at opnå de forventede resultater fra en aggregateconcatenation-forespørgsel, skal du anvende enhver Transact-SQL-funktion eller -udtryk på kolonnerne i SELECT-listen i stedet for i ORDER BY-udtrykket.

Din problematiske forespørgsel anvender ingen udtryk på kolonner i ORDER BY klausul.

Artiklen fra 2005 Bestillingsgarantier i SQL Server... angiver

Af årsager til bagudkompatibilitet giver SQL Server understøttelse af tildelinger af typen SELECT @p =@p + 1 ... BESTIL EFTER i det øverste område.

I de planer, hvor sammenkædningen fungerer, som du forventede, beregner skalaren med udtrykket [Expr1003] = Scalar Operator([@x]+[Expr1004]) vises over sorteringen.

I planen, hvor den ikke fungerer, vises beregningsskalaren under sorteringen. Som forklaret i dette forbindelseselement fra 2006, hvor udtrykket @x = @x + [msg] vises under den sortering, den evalueres for hver række, men alle evalueringerne ender med at bruge præ-tildelingsværdien @x . I et andet lignende Connect Item fra 2006 talte svaret fra Microsoft om at "løse" problemet.

Microsofts svar på alle de senere Connect-emner om dette problem (og der er mange) angiver, at dette simpelthen ikke er garanteret

Eksempel 1

vi giver ingen garantier for rigtigheden af ​​sammenkædningsforespørgsler (som at bruge variable tildelinger med datahentning i en bestemt rækkefølge). Forespørgselsoutputtet kan ændre sig i SQL Server 2008 afhængigt af planvalget, data i tabellerne osv. Du bør ikke stole på, at dette fungerer konsekvent, selvom syntaksen tillader dig at skrive en SELECT-sætning, der blander hentning af ordnede rækker med variabel tildeling.

Eksempel 2

Den adfærd, du ser, er af design. Brug af tildelingsoperationer (sammenkædning i dette eksempel) i forespørgsler med ORDER BY-klausul har udefineret adfærd. Dette kan ændre sig fra udgivelse til udgivelse eller endda inden for en bestemt serverversion på grund af ændringer i forespørgselsplanen. Du kan ikke stole på denne adfærd, selvom der er løsninger. Se KB-artiklen nedenfor for flere detaljer:
http://support.microsoft.com/kb/287515 Den ENESTE garanterede mekanisme er følgende:

  1. Brug markøren til at gå gennem rækkerne i bestemt rækkefølge og sammenkæde værdierne
  2. Brug til xml-forespørgsel med ORDER BY til at generere de sammenkædede værdier
  3. Brug CLR-aggregat (dette fungerer ikke med ORDER BY-klausul)

Eksempel 3

Den adfærd, du ser, er faktisk af design. Dette har at gøre med, at SQL er et sæt-manipulationssprog. Alle udtryk i SELECT-listen (og dette inkluderer også tildelinger) er ikke garanteret at blive udført nøjagtigt én gang for hver outputrække. Faktisk prøver SQL queryoptimizer hårdt på at udføre dem så få gange som muligt. Dette vil give forventede resultater, når du beregner værdien af ​​variablen baseret på nogle data i tabellerne, men når den værdi, du tildeler, afhænger af den tidligere værdi af den samme variabel, kan resultaterne være ret uventede. Hvis forespørgselsoptimeringsværktøjet flytter udtrykket til et andet sted i forespørgselstræet, kan det blive evalueret færre gange (eller kun én gang, som i et af dine eksempler). Dette er grunden til, at vi ikke anbefaler at bruge "iteration"-typetildelingerne til at beregne aggregerede værdier. Vi oplever, at XML-baserede løsninger ... normalt fungerer godt for kunderne

Eksempel 4

Selv uden ORDER BY garanterer vi ikke, at @var =@var +vil producere den sammenkædede værdi for enhver sætning, der påvirker flere rækker. Den højre side af udtrykket kan evalueres enten én eller flere gange under udførelse af forespørgsler, og adfærden som sagt er planafhængig.

Eksempel 5

Variabeltildelingen med SELECT-sætning er en proprietær syntaks (kun T-SQL), hvor adfærden er udefineret eller planafhængig, hvis der produceres flere rækker. Hvis du har brug for at udføre strengsammenkædning, skal du bruge en SQLCLR-sammenkædning eller FOR XML-forespørgselsbaseret sammenkædning eller andre relationelle metoder.



  1. Sådan får du året og måneden fra en dato i MySQL

  2. indlæs data spinner fra sqlite og mysql

  3. Hvordan bruger jeg ROW_NUMBER()?

  4. Hvordan kan jeg simulere en array-variabel i MySQL?