webForumDet fria alternativet

splitta sträng

9 svar · 456 visningar · startad av doggelito

doggelitoMedlem sedan juni 20003 076 inlägg
#1

yoo!

har denna utmärkta function, den splittar en sträng och lägger värdena i en tmp tabell som man sedan kan joina med.
men, det händer då och då att jag behöver splitta en sträng som är längre än 8000 tecken och då räcker denna inte längre till.
skulle man kunna byta till datatypen text i funktionen på nått vis? eller finns det nått annat sätt att splitta på?

ALTER FUNCTION ufSplit(@sText varchar(8000), @sDelim varchar(20) = ' ')
	RETURNS @retArray TABLE (idx smallint Primary Key, value varchar(8000))
AS
BEGIN

	DECLARE @idx smallint,
	@value varchar(8000),
	@bcontinue bit,
	@iStrike smallint,
	@iDelimlength tinyint

	IF @sDelim = 'Space'
		BEGIN
			SET @sDelim = ' '
		END

	SET @idx = 0
	SET @sText = LTrim(RTrim(@sText))
	SET @iDelimlength = DATALENGTH(@sDelim)
	SET @bcontinue = 1

	IF NOT ((@iDelimlength = 0) or (@sDelim = 'Empty'))
		BEGIN
		WHILE @bcontinue = 1
			BEGIN

				--If you can find the delimiter in the text, retrieve the first element and
				--insert it with its index into the return table.
 
				IF CHARINDEX(@sDelim, @sText)>0
					BEGIN
						SET @value = SUBSTRING(@sText,1, CHARINDEX(@sDelim,@sText)-1)
						BEGIN
							INSERT @retArray (idx, value)
							VALUES (@idx, @value)
						END
			
						--Trim the element and its delimiter from the front of the string.
						--Increment the index and loop.
						SET @iStrike = DATALENGTH(@value) + @iDelimlength
						SET @idx = @idx + 1
						SET @sText = LTrim(Right(@sText,DATALENGTH(@sText) - @iStrike))
		
					END
				ELSE
					BEGIN
						--If you can’t find the delimiter in the text, @sText is the last value in
						--@retArray.
						SET @value = @sText
						BEGIN
							INSERT @retArray (idx, value)
							VALUES (@idx, @value)
						END
						--Exit the WHILE loop.

						SET @bcontinue = 0
					END
			END
		END
	ELSE
		BEGIN
			WHILE @bcontinue=1
			BEGIN
				--If the delimiter is an empty string, check for remaining text
				--instead of a delimiter. Insert the first character into the
				--retArray table. Trim the character from the front of the string.
				--Increment the index and loop.
				IF DATALENGTH(@sText)>1
					BEGIN
						SET @value = SUBSTRING(@sText,1,1)
						BEGIN
							INSERT @retArray (idx, value)
							VALUES (@idx, @value)
						END
						SET @idx = @idx+1
						SET @sText = SUBSTRING(@sText,2,DATALENGTH(@sText)-1)
					END
				ELSE
					BEGIN
						--One character remains.
						--Insert the character, and exit the WHILE loop.
						INSERT @retArray (idx, value)
						VALUES (@idx, @sText)
						SET @bcontinue = 0	
					END
			END
		END

RETURN
END
LarsGMedlem sedan dec. 200012 464 inlägg
#2

Du kan inte ha parametrar av typen text så det går inte. Varifrån kommer dessa strängar? Borde du inte ha dessa värden i en tabell istället?

doggelitoMedlem sedan juni 20003 076 inlägg
#3

Strängarna kommer oftast ifrån en asp-sida.
Ex.
På en sida listar jag en massa poster och efter varje post finns en checkbox där man markerar posten.
Man markerar ett par stycken poster och klickar på raderaknapp, alla posters id:n skickas in som en sträng i en SP som splittar den och raderar posterna.

ALTER       PROCEDURE upNewsDelete
	@IDno varchar(8000)

AS

BEGIN
	SET NOCOUNT ON

	DELETE News 
		WHERE IDno IN (SELECT value FROM ufSplit(@IDno, ','))

	SELECT @@rowcount
END

Visst, man skulle kunna loopa på aspsidan istället och skicka in en post åt gången men, nja.

Problemet uppstår alltså då man markerar för många poster så strängen blir för lång (har man höga id-nummer så behövs det inte så många poster innan man kommer upp i 8000 tecken)

LarsGMedlem sedan dec. 200012 464 inlägg
#4

Men om du har en 4-bytes integer som nyckel så räcker det med 12 byte i text-format och då får du ändå plats med mer än 600 värden.

Visst, man skulle kunna loopa på aspsidan istället och skicka in en post åt gången men, nja.

Varför bara en post åt gången?

doggelitoMedlem sedan juni 20003 076 inlägg
#5

Varför bara en post åt gången?

Jag förstår inte riktigt vad du menar här. :q
Hur kan man annars radera flera poster åt gången?
Alltså om checkboxarna har ett id:nr som value så kan jag ju loopa igenom alla boxar och köra en delete i varje loop.

Ovan var ett exempel, här är ett till:
På en asp-sida skickar man nyhetsbrev.
Man skriver ett ämne samt en bodytext och i en textarea fyller man i alla mottagaradresser man ska skcka till (kommaseparerade).
Infon skickas sedan in i databasen som tre strängar, ämne, body och mottagare.
Databasen splittar sedan upp alla mottagare och gör en insert för varje in i en kö-tabell som hanterar alla mailutskick.
Och låt oss säga att en epostadress är 15 tecken lång plus ett kommatecken mellan varje så kan man alltså bara skicka in 500 adresser, vilket kanske inte räcker så långt alla ggr.

Det finns ju flera sätt att lösa detta på, man kan t.ex köra en len() på asp-sidan och skicka en varning att man fyllt i för många adresser osv. men jag skulle gärna vilja lösa det hela i sql-servern om det går!

Du kan inte ha parametrar av typen text så det går inte.

Hmm, jag har bestämt för mig att jag använt text som parameter i SP:s, men du kanske bara menar i UDF:s, eller?

Skulle man inte kunna skicka in mottagarna som typen text i SP:n och där dela upp den i flera varchars på nått vis? Eller är text helt omöjligt att formatera/konvertera?

Puhh, många frågor och funderingar blev det! :)

LarsGMedlem sedan dec. 200012 464 inlägg
#6

Du skrev att du skulle kunna göra en loop i ASP och skicka in en post åt gången och då tänkte jag mig att du menade

' start transaction
for each f in formname
    sql = "delete from t where id = " & f.value
    connect.execute sql,,128
next
'commit transaction

och då menade jag bara att du skulle kunna samla ihop så många id som du får plats med innan du gör execute.

' start transaction
l = 0
c = 0
sql = ""
for each f in formname
     if l + len(f.value) > 7998 then
        connect.execute sql & ")",,128
        l = 0
     end if
     if  l = 0 then 
         sql = "delete from t where id in ( " 
         c = 0
     end if
      if c > 0 then sql = sql & "," 
      sql = sql & f.value
     l = len(sql)
     c = c + 1 
next
if c > 0 then connect.execute sql & ")",,128
'commit transaction

Jag menade variabel när jag skrev det där om parametrar och textdatatyp. Det finns dock begränsningar som att det inte går att använda len på en variabel av typen text. Visst, det går att ha flera 8000 tecken parametrar men det känns lite oflexibelt.

Men det verkar i alla fall konstigt att någon skulle sitta och kryssa för flera hundra checkboxar i ett formulär. Kan du inte kategorisera saker lite?

doggelitoMedlem sedan juni 20003 076 inlägg
#7

Kan du inte kategorisera saker lite?

Mjao, det kan jag kanske göra i de flesta fall.
Det vore bara så enkelt att bara tjoffa in en lång skön sträng i databasen och sedan sköta uppdelningen där.
Om inte annat så får man fruktat snabbladdade sidor med bara ett databasanrop.

Men:
Eftersom DU inte verkar ha gjort en liknande hantering av strängar så måste väl det betyda att jag är fel ute! ;)

Får ta och fundera lite, får se om man kommer på nån bra lösning! :)

doggelitoMedlem sedan juni 20003 076 inlägg
#8

Hmm, denna artikel var lite för avancerad för mig men visst verkar detta vara vad jag söker?! Eller?
Man skickar in en sträng (i deras fall i formatet ntext) som sedan splittas upp och skickas tillbaka som en tabell.
http://www.sommarskog.se/arrays-in-sql.html#iterative

LarsGMedlem sedan dec. 200012 464 inlägg
#9

Ja, man skall använda datalength ja. Jo det verkar vara kuckelimaffens,precis vad du vill ha. Men som sagt så är det inte något som jag skulle använda.

Jag har nog mest spridit förvirring i denna tråd :)

doggelitoMedlem sedan juni 20003 076 inlägg
#10

Jag gjorde ett litet snabbt test på en enkel select och den verka hämta så som jag vill. :)

Men som sagt så är det inte något som jag skulle använda.

Då blir man ju genast orolig!
Varför vill du inte använda en sådan funktion?

Har du någon bättre lösning på stränghantering? Eller undviker du helt enkelt långa strängar! :q

135 ms totalt · 3 externa anrop · v20260731065814-full.3ab8d573
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)