2016-06-30 37 views
5

In un database SqlServer che utilizzo, il nome del database è qualcosa come StackExchange.Audio.Meta o StackExchange.Audio o StackOverflow. Per pura fortuna questo è anche l'url per un sito web. Ho solo bisogno di dividerlo sui punti e invertire: meta.audio.stackexchange. Aggiungendo http:// e .com e ho finito. Ovviamente Stackoverflow non ha bisogno di alcuna retromarcia.Concatena il risultato di uno String_Split ordinato in una variabile

Utilizzando 2016 string_split funzione di SqlServer posso facile scissione e riordinare il suo risultato:

select value 
from string_split(db_name(),'.') 
order by row_number() over(order by (select 1)) desc 

Questo mi dà

| Value  | 
----------------- 
| Meta   | 
| Audio   | 
| StackExchange | 

Come ho bisogno di avere l'url in una variabile speravo di concatenare usando questo answer così il mio tentativo assomiglia a questo:

declare @revname nvarchar(150) 
select @revname = coalesce(@revname +'.','') + value 
from string_split(db_name(),'.') 
order by row_number() over(order by (select 1)) desc 

Tuttavia, questo mi restituisce solo l'ultimo valore, StackExchange. Ho già notato gli avvertimenti su quella risposta che questo trucco funziona solo per determinati piani di esecuzione come spiegato here.

Il problema sembra essere causato dalla clausola order by. Senza di ciò ottengo tutti i valori, ma poi nell'ordine sbagliato. Ho provato ad aggiungere la funzione ltrim e rtrim come suggerito nell'articolo di Microsoft, così come una sottoquery ma finora senza fortuna.

Esiste un modo per spingere il motore di query di Sql Server 2016 a concatenare il risultato ordinato da quello string_split in una variabile?

So che posso usare for XML o anche un semplice cursore per ottenere il risultato che mi serve ma non voglio rinunciare ancora a questa soluzione elegante.

Poiché sto eseguendo questa operazione su Stack Exchange Data Explorer, non posso utilizzare le funzioni, poiché non abbiamo il permesso di crearle. Posso fare procedure memorizzate ma speravo di poterle eludere.

Ho preparato un SEDE Query per sperimentare. I nomi dei database per aspettarsi sono o senza punti e aka StackOverflow, con 1 punto: StackOverflow.Meta o 2 punti, `StackExchange.Audio.Meta, l'elenco completo delle banche dati è here

+0

Perché non http://data.stackexchange.com/meta.avp/query/506813? Oh e riguardo al tuo desiderio di usare il metodo di assegnazione variabile non c'è mai alcuna garanzia che funzionerà. http://stackoverflow.com/questions/15138593/nvarchar-concatenation-index-nvarcharmax-inexplicable-behavior/15163136#15163136 –

+0

Mi rendo conto che sto usando un comportamento non definito, quindi lo accetto anche come risposta. – rene

+0

Non rispondere veramente alla domanda, ma se stai generando URL con tutte queste manipolazioni di stringhe, perché non avere una tabella di ricerca? Nella tua query SEDE stai già facendo cose strane ('when 'audio' quindi' Avp') quindi non è meglio avere una tabella di traduzione per tutto questo? – DavidG

risposta

3

Penso che si sta over-complicare le cose. Si potrebbe usare PARSENAME:

SELECT 'http://' + PARSENAME(db_name(),1) + 
     ISNULL('.' + PARSENAME(db_name(),2),'') + ISNULL('.'+PARSENAME(db_name(),3),'') 
     + '.com' 
+0

Funziona bene, e mi piace come ignori totalmente il mio tentativo;). Non è il caso in cui [parsename] (https://msdn.microsoft.com/en-us/library/ms188006.aspx) è stato originariamente progettato per ma non avrei controllato o provato questo se tu (e Martin) non avevi t indicalo a me. Grazie. – rene

+0

@ rene Ho solo pensato che il tuo approccio fosse eccessivamente complicato, mi dispiace. Non avevo visto il commento di MartinSmith, ma ora sono più fiducioso di averlo letto ;-) – Lamak

1

Questo è esattamente il motivo per cui ho la sequenza di presentazione (PS) nel mio funzione split. Spesso le persone si fanno beffe dell'uso di una UDF per tali elementi, ma in genere si tratta di un singolo colpo per analizzare qualcosa per un consumo successivo.

Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.') 

Returns

Key_PS Key_Value 
1  meta 
2  audio 
3  stackexchange 

L'UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@delimeter varchar(10)) 
--Usage: Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.') 
--  Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ') 
--  Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|') 

Returns @ReturnTable Table (Key_PS int IDENTITY(1,1) NOT NULL , Key_Value varchar(max)) 

As 

Begin 
    Declare @intPos int,@SubStr varchar(max) 
    Set @IntPos = CharIndex(@delimeter, @String) 
    Set @String = Replace(@String,@[email protected],@delimeter) 
    While @IntPos > 0 
     Begin 
     Set @SubStr = Substring(@String, 0, @IntPos) 
     Insert into @ReturnTable (Key_Value) values (@SubStr) 
     Set @String = Replace(@String, @SubStr + @delimeter, '') 
     Set @IntPos = CharIndex(@delimeter, @String) 
     End 
    Insert into @ReturnTable (Key_Value) values (@String) 
    Return 
End 
+0

Una funzione UDF è fantastica e io adoro e l'avrei usata. Sfortunatamente su SEDE non abbiamo il permesso di creare la funzione. – rene

+0

@rene Ancora rinfrescante per usare semplici mortali per vedere qualcuno che i rappresentanti di 22K fanno una domanda. –

+0

Beh, sì dopo aver sbattuto la testa per 2 ore ho già passato così tanto tempo che non volevo mollare .... – rene

1

soluzione Probabilmente meno elegante, ma ci vogliono solo poche righe e funziona con qualsiasi numero di punti.

;with cte as (--build xml 
    select 1 num, cast('<str><s>'+replace(db_name(),'.','</s><s>')+'</s></str>' as xml) str 
) 
,x as (--make table from xml 
    select row_number() over(order by num) rn, --add numbers to sort later 
     t.v.value('.[1]','varchar(50)') s 
    from cte cross apply cte.str.nodes('str/s') t(v) 
) 
--combine into string 
select STUFF((SELECT '.' + s AS [text()] 
      FROM x 
      order by rn desc --in reverse order 
      FOR XML PATH('') 
      ), 1, 1, '') name 
1

C'è un modo per spostare il server Sql 2016 query del motore di concatenare il risultato ordinato da che string_split in una variabile?

Si può semplicemente utilizzare CONCAT:

DECLARE @URL NVARCHAR(MAX) 
SELECT @URL = CONCAT(value, '.', @URL) FROM STRING_SPLIT(DB_NAME(), '.') 
SET @URL = CONCAT('http://', LOWER(@URL), 'com'); 

L'inversione si ottiene l'ordine dei parametri per CONCAT. Here's an example.

Cambia StackExchange.Garage.Meta a http://meta.garage.stackexchange.com.

Questo può essere usato per dividere e invertire le stringhe in generale, ma si noti che lascia un delimitatore finale. Sono sicuro che potresti aggiungere qualche logica o un COALESCE lì per evitare che ciò accada.

Si noti inoltre che vNext aggiungerà STRING_AGG.

1

Per rispondere alla 'X' di questo problema XY e per indirizzare lo switch HTTPS (in particolare per i siti Meta) e altre modifiche al nome del sito, ho scritto il seguente SEDE query che genera tutti i nomi dei siti nel formato utilizzato su network site list.

SELECT name, 
    LOWER('https://' + 
    IIF(PATINDEX('%.Mathoverflow%', name) > 0, 
    IIF(PATINDEX('%.Meta', name) > 0, 'meta.mathoverflow.net', 'mathoverflow.net'), 
     IIF(PATINDEX('%.Ubuntu%', name) > 0, 
     IIF(PATINDEX('%.Meta', name) > 0, 'meta.askubuntu.com', 'askubuntu.com'), 
     IIF(PATINDEX('StackExchange.%', name) > 0, 
      CASE SUBSTRING(name, 15, 200) 
      WHEN 'Audio' THEN 'video' 
      WHEN 'Audio.Meta' THEN 'video.meta' 
      WHEN 'Beer' THEN 'alcohol' 
      WHEN 'Beer.Meta' THEN 'alcohol.meta' 
      WHEN 'CogSci' THEN 'psychology' 
      WHEN 'CogSci.Meta' THEN 'psychology.meta' 
      WHEN 'Garage' THEN 'mechanics' 
      WHEN 'Garage.Meta' THEN 'mechanics.meta' 
      WHEN 'Moderators' THEN 'communitybuilding' 
      WHEN 'Moderators.Meta' THEN 'communitybuilding.meta' 
      WHEN 'Photography' THEN 'photo' 
      WHEN 'Photography.Meta' THEN 'photo.meta' 
      WHEN 'Programmers' THEN 'softwareengineering' 
      WHEN 'Programmers.Meta' THEN 'softwareengineering.meta' 
      WHEN 'Vegetarian' THEN 'vegetarianism' 
      WHEN 'Vegetarian.Meta' THEN 'vegetarianism.meta' 
      WHEN 'Writers' THEN 'writing' 
      WHEN 'Writers.Meta' THEN 'writing.meta' 
      ELSE SUBSTRING(name, 15, 200) 
      END + '.stackexchange.com', 
      IIF(PATINDEX('StackOverflow.%', name) > 0, 
      CASE SUBSTRING(name, 15, 200) 
      WHEN 'Br' THEN 'pt' 
      WHEN 'Br.Meta' THEN 'pt.meta' 
      ELSE SUBSTRING(name, 15, 200) 
      END + '.stackoverflow.com', 
      IIF(PATINDEX('%.Meta', name) > 0, 
       'meta.' + SUBSTRING(name, 0, PATINDEX('%.Meta', name)) + '.com', 
       name + '.com' 
      ) 
     ) 
     ) 
    ) 
    ) + '/' 
) 
    FROM sys.databases WHERE database_id > 5