How to extract an ID number from a URL string in SQL? - sql

I am trying to extract an ID from a URL and running into some issues. The URL's will look something like this:
http://www.website.com/news/view.aspx?id=95
http://www.website.com/news/view.aspx?id=20&ReturnURL=%2fnews%2fview.aspx%3fid%3d20
I am trying to return back the number following "?id=" and nothing after the number. I will then convert it to an INT in reference to another table. Any suggestions as how to do this properly?

Use charindex to find the position of ?id and stuff to remove the characters that is before ?id. Then you use left to return the characters to the next &
declare #T table
(
URL varchar(100)
);
insert into #T values
('http://www.website.com/news/view.aspx?id=95'),
('http://www.website.com/news/view.aspx?id=20&ReturnURL=%2fnews%2fview.aspx%3fid%3d20');
select left(T2.URL, charindex('&', T2.URL) - 1) as ID
from #T as T
cross apply (select stuff(T.URL, 1, charindex('?id', T.URL) + 3, '')+'&') as T2(URL);

Here is an option that you can use when you want to find the value of any parameter value within a URL, it also supports parsing text values that contain a URL
DECLARE #Param varchar(50) = 'event'
DECLARE #Data varchar(8000) = 'User Logged into https://my.website.org/default.aspx?id=3066&event=49de&event=true from ip'
DECLARE #ParamIndex int = (select PatIndex('%'+#param+'=%', #Data)+LEN(#param)+1)
-- #ParamValueSubstring chops off everthing before the first instance of the parameter value
DECLARE #ParamValueSubstring varchar(8000) = SubString(#Data, #ParamIndex, 8000)
SELECT #ParamValueSubstring as ParamSubstring
DECLARE #SpaceIndex int = (SELECT CHARINDEX(' ', #ParamValueSubstring))-1
DECLARE #AmpIndex int = (SELECT CHARINDEX('&', #ParamValueSubstring))-1
DECLARE #valueLength int = -1
-- find first instance of ' ' or & after parameter value
IF #SpaceIndex = -1
SET #valueLength = #AmpIndex
ELSE IF #AmpIndex = -1
SET #valueLength = #SpaceIndex
ELSE IF #SpaceIndex < #AmpIndex
SET #valueLength = #SpaceIndex
ELSE
SET #valueLength = #AmpIndex
IF(#valueLength = -1) -- check to see if there was no space or '&' following the parameter value
BEGIN
SET #valueLength = 8000
END
select Left(#ParamValueSubstring, #valueLength) as ParamValue
-- approach similar to idea function found here http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/extracting-numbers-with-sql-server/

I'm not totally clear on what you're asking. Are you asking how to get the value of id from the url when you are in the asp.net application? Then in the code behind you can
In c#
string id = Request.QueryString["id"]; // returns null if id not found
Reference
From this SO question Try this for integers:
int id;
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}

You could do it in an SQL function, like this:
declare #URL varchar(100)
--set #URL = 'http://www.website.com/news/view.aspx?id=95'
set #URL = 'http://www.website.com/news/view.aspx?id=20&ReturnURL=%2fnews%2fview.aspx%3fid%3d20'
Set #URL = CASE charindex('&',#URL)
WHEN 0 then #URL else substring(#url,1,charindex('&',#URL)-1) end
select #URL,SUBSTRING(#URL,CHARINDEX('?id=',#URL)+4,99)
Both examples are in there, comment either one to see result

Related

Replace substring between two delimiters or until the end of string

In a procedure in SQL Server 2008 I need to replace a substring between 2 identifiers. I do not know the complete strings to be replaced, or if the second identifier exists.
If the terminator identifier is not present, I would need the end of the string to be considered one. Also, the identifiers could be the same.
DECLARE #startIdenfier VARCHAR(10) = 'the'
DECLARE #endIdenfier VARCHAR(10) = 'the'
DECLARE #newString VARCHAR(20) = 'new string that'
Sample input / output:
'This is the old string that the process needs to be applied on.' ->
'This is the new string that the process needs to be applied on.'
'This is the old string' ->
'This is the new string that'
SET #endIdenfier = 'I'
'This is the old string that I don't like' ->
'This is the new string that I don't like''
It is a generic replace and I havn't been able to find the proper way to do it, since the REPLACE function does not accept indexes.
EDIT: This community is awesome. I am sorry I cannot select multiple accepted solutions, but I thank you all for your help. I'll try all solutions already posted (besides the already accepted one which I tested) and up-vote individually.
--Find the start index plus the length of the string found (plus one for the space)
SET #startIdx = CHARINDEX(#startIdentifier, #initialString, 1) + LEN(#startIdentifier) + 1
--Find the next occurrence of the end identifier (minus one for the space)
SET #endIdx = CHARINDEX(#endIdentifier, #initialString, #startIdx) - 1;
--end not found?
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
--Use the STUFF function to remove the old chars from endindex-startindex, and insert the new string at the startindex
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString)
In full:
DECLARE #startIdenfier Varchar(10)
SET #startIdenfier = 'the'
DECLARE #endIdenfier Varchar(10)
SET #endIdenfier = 'the'
DECLARE #newString Varchar(100)
SET #newString = 'new string that'
DECLARE #initialString VARCHAR(256) = 'this is the old string that the process needs to be applied on';
DECLARE #startIdx INT;
SET #startIdx = CHARINDEX(#startIdenfier, #initialString, 1) + LEN(#startIdenfier) + 1;
DECLARE #endIdx INT;
SET #endIdx= CHARINDEX(#endIdenfier, #initialString, #startIdx) - 1;
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
DECLARE #results VARCHAR(256);
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString);
SELECT #results
You could do something like this:
/*Declare necessary variables*/
DECLARE #startIndex INT
DECLARE #endIndex INT
DECLARE #startReplace INT
DECLARE #lengthReplace INT
DECLARE #replaceString VARCHAR(500)
/*Get the index of the start/end idenfier*/
SELECT #startIndex = CHARINDEX ( #startIdenfier , #originalString)
SELECT #endIndex = CHARINDEX ( #startIdenfier , #originalString, #startIndex+1)
/*In case the end idenfier doesn't exist*/
IF #endIndex = 0
SET #endIndex = LEN(#originalString) + 1
SET #startReplace = #startIndex + len(#startIdenfier)
SET #lengthReplace = #endIndex - #startReplace
SELECT STUFF(#originalString, #startReplace, #lengthReplace, #newString)
I think you will need to incorporate the PATINDEX function and create the pattern by using your start and end identifiers. That will satisfy the condition where both start and end identifiers are present...
DECLARE #OldString nvarchar(max)
DECLARE #NewString nvarchar(max)
DECLARE #StartLocation bigint
DECLARE #Pattern nvarchar(200) = '%' + #StartIdentifier + ' % ' + #EndIdentifer + '%'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located, then you can get the string to be replaced by substringing the 'old complete string', starting at position (#StartLocation + Length of #StartIdentifier + 1). To determine the length for SUBSTRING, you need to locate the position of #EndIdentifier, using CHARINDEX of the old complete string beginning at ( #StartLocation + Length of #StartIdentifier + 1). Subtract ( #StartLocation + Length of StartIdentifier + 1) from result of CHARINDEX.
SELECT #OldString = SUBSTRING('complete old string', #StartLocation + LEN(#StartIdentifier) + 1, CHARINDEX(' ' + #EndIdentifier, 'old complete string', #StartLocation + LEN(#StartIdentifier) + 1) - (#StartLocation + LEN(#StartIdentifier) + 1)))
You can at this point do a straight forward REPLACE to get the new string.
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
"If there is no 'terminator' identifier, I would need the end of the
string to be considered one."
If the initial pattern was not located, we fall back to search for the #StartIdentifier only. For this you can reset the pattern to contain the #StartIdentifier only...
SELECT #Pattern = '%' + #StartIdentifier + ' %'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located then you can get the old string to replace by SUBSTRING starting at ( #StartLocation + Length of #StartIdentifier + 1 ), with a length of 'old complete string' length - ( #StartLocation + Length of #StartIdentifier + 1 )...
SELECT #OldString = SUBSTRING('old complete string', #StartLocation + LEN(#StartIdentifier) + 1, LEN('old complete string') - (#StartLocation + LEN(#StartIdentifier) + 1))
You can then REPLACE...
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
Something like this...
DECLARE #initialString VARCHAR(32) = '1234567890123456789'
DECLARE #startIdentifier VARCHAR(32) = '34'
DECLARE #endIdentifier VARCHAR(32) = '34'
DECLARE #newString VARCHAR(32) = 'ABC'
DECLARE #headChars INT = CHARINDEX(#startIdentifier, #initialString, 1)
IF #headChars > 0
SET #headChars = #headChars + LEN(#startIdentifier) - 1
DECLARE #bodyChars INT = CHARINDEX(#endIdentifier, #initialString, #headChars + 1)
IF #bodyChars > 0
SET #bodyChars = LEN(#initialString) - #bodyChars + 1
SELECT
LEFT(#initialString, #headChars)
+ #newString
+ RIGHT(#initialString, #bodyChars)
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b8a179d0e63840dfa60905d9951e4b22
For example...
'1234567890123456789'
'34' => Start # 1 => Found # 3 => keep chars 1->4
'34' => Start # 5 => Found # 13 => keep chars 13->end
Just use STUFF and CHARINDEX. Figure out:
the position at which replacement begins (position of the + length of the)
the position at which replacement ends (position of the starting from see above)
And subtract the positions to calculate the number of characters to replace.
DECLARE #string VARCHAR(100) = 'This is the old string that the process needs to be applied on.'
DECLARE #replace VARCHAR(100) = 'NEW STRING THAT '
DECLARE #delim1 VARCHAR(100) = 'the '
DECLARE #delim2 VARCHAR(100) = 'the '
DECLARE #pos1 INT = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
DECLARE #pos2 INT = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT the process needs to be applied on."
SET #delim2 = 'xxx'
SET #pos1 = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
SET #pos2 = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT "
Note: spaces should be a part of search delimiters instead of the logic. the should not match them and threfore.

Why is SQL output parameter always null

I have the following SP
CREATE PROCEDURE [dbo].[GetBaseSixtyTwoString]
#a_number_to_convert int,
#v_temp_val nvarchar(256) output
AS
DECLARE #v_modulo INTEGER;
DECLARE #v_temp_int decimal(38) = #a_number_to_convert;
DECLARE #v_temp_char VARCHAR(1);
DECLARE #c_base62_digits VARCHAR(62) = '0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ';
IF ( #a_number_to_convert = 0 )
BEGIN
SET #v_temp_val = '5';
END
WHILE ( #v_temp_int <> 0 )
BEGIN
SET #v_modulo = #v_temp_int % 62;
SET #v_temp_char = substring( #c_base62_digits, #v_modulo + 1, 1 );
SET #v_temp_val = #v_temp_char + #v_temp_val;
SET #v_temp_int = floor(#v_temp_int / 62);
END
I am calling it like this:
declare #shorturl nvarchar(256)
exec dbo.GetBaseSixtyTwoString 1, #shorturl output
But the variable #shorturl always returns null
However if I put print statements in the SP I can see that #v_temp_val is indeed getting the correct value.
What am I missing?
You need to initialise #v_temp_val inside the stored procedure to non-NULL value, to ''.
If #v_temp_val is NULL, then this line would still result in NULL:
SET #v_temp_val = #v_temp_char + #v_temp_val;
because "value" + NULL = NULL
check if any value you put into variable #v_temp_val is null. note that any non-null value + NULL will result to NULL:
SET #v_temp_val = ISNULL(#v_temp_char, '') + ISNULL(#v_temp_val, '');

Replacing a string in a text field

I have a column in my database table which has lows of text and lows of rows. In the text, a url needs to be changed for every row. In each row the url can exist more than once.
Can I use the replace function to change all the urls in the text field in my database table without affecting the rest of the text in that same column?
Thanks
Use REPLACE()
UPDATE table SET text = REPLACE(text, 'from', 'to')
Make precise from: like with http://url_from.com/ to http://url_to.com/
Based on article posted at https://web.archive.org/web/20150521050102/http://sqlserver2000.databases.aspfaq.com:80/how-do-i-handle-replace-within-an-ntext-column-in-sql-server.html
I needed to write a find and replace for CHAR(146) ` in a text field. Above article for fort nText and the same solution for text worked with nText with the following changes:
- VARCHAR(32) from nVARCHAR(32)
- use #lenOldString = DATALENGTH(#oldString) instead of SET #lenOldString = DATALENGTH(#oldString)/2.
DECLARE
#TextPointer BINARY(16),
#TextIndex INT,
#oldString VARCHAR(32),
#newString VARCHAR(32),
#lenOldString INT,
#currentDataID INT;
SET #oldString = '’';
SET #newString = '''';
IF CHARINDEX(#oldString, #newString) > 0
BEGIN
PRINT 'Quitting to avoid infinite loop.';
END
ELSE
BEGIN
--Need the for nText fields
--SET #lenOldString = DATALENGTH(#oldString)/2
--Use this for text fields
SET #lenOldString = DATALENGTH(#oldString)
DECLARE irows CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY FOR
SELECT
DataID
FROM
dbo.tbData
WHERE
PATINDEX('%'+#oldString+'%', TextData) > 0;
OPEN irows;
FETCH NEXT FROM irows INTO #currentDataID;
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT
#TextPointer = TEXTPTR(TextData),
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
SELECT #TextPointer, #TextIndex
WHILE
(
SELECT
PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID
) > 0
BEGIN
SELECT
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)-1
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
UPDATETEXT dbo.tbData.TextData #TextPointer #TextIndex #lenOldString #newString;
END
FETCH NEXT FROM irows INTO #currentDataID;
END
CLOSE irows;
DEALLOCATE irows;
END

Find a specific substring using Transact-SQL

I need to pull a specific substring from a string of the form:
foo=abc;bar=def;baz=ghi
For example, how would I get the value of "bar" from that string?
You can use charindex and substring. For example, to search for the value of "baz":
declare #str varchar(128)
set #str = 'foo=abc;bar=def;baz=ghi'
-- Make sure #str starts and ends with a ;
set #str = ';' + #str + ';'
select substring(#str,
charindex(';baz=',#str) + len(';baz='),
charindex('=',#str,charindex(';baz=',#str)) - charindex(';baz=',#str) - 1)
Or for the value of "foo" at the start of the string:
select substring(#str,
charindex(';foo=',#str) + len(';foo='),
charindex('=',#str,charindex(';foo=',#str)) - charindex(';foo=',#str) - 1)
Here's a UDF to accomplish this (more readable version inspired by BlackTigerX's answer):
create function dbo.FindValueInString(
#search varchar(256),
#name varchar(30))
returns varchar(30)
as
begin
declare #name_start int
declare #name_length int
declare #value_start int
declare #value_end int
set #search = ';' + #search
set #name_start = charindex(';' + #name + '=',#search)
if #name_start = 0
return NULL
set #name_length = len(';' + #name + '=')
set #value_start = #name_start + #name_length
set #value_end = charindex(';', #search, #value_start)
return substring(#search, #value_start, #value_end - #value_start)
end
As you can see, this isn't easy in Sql Server :) Better do this in the client language, or normalize your database so the substrings go in their own columns.
I have a generalized solution that works for this problem:
CREATE FUNCTION [dbo].[fn_StringBetween]
(
#BaseString varchar(max),
#StringDelim1 varchar(max),
#StringDelim2 varchar(max)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE #at1 int
DECLARE #at2 int
DECLARE #rtrn varchar(max)
SET #at1 = CHARINDEX(#StringDelim1, #BaseString)
IF #at1 > 0
BEGIN
SET #rtrn = SUBSTRING(#BaseString, #at1
+ LEN(#StringDelim1), LEN(#BaseString) - #at1)
SET #at2 = CHARINDEX(#StringDelim2, #rtrn)
IF #at2 > 0
SET #rtrn = LEFT(#rtrn, #at2 - 1)
END
RETURN #rtrn
END
so if you run (just wrap your original string to be searched with ';' at beginning and end):
PRINT dbo.fn_StringBetween(';foo=abc;bar=def;baz=ghi;', ';bar=', ';')
you will get 'def' returned.
look into the PATINDEX function. It has wildcard matching which should help you..
you can use this function
alter function FindValue(#txt varchar(200), #find varchar(200))
returns varchar(200)
as
begin
declare
#firstPos int,
#lastPos int
select #firstPos = charindex(#find, #txt), #lastPos = charindex(';', #txt, #firstPos+5)
select #lastPos = len(#txt)+1 where #lastPos = 0
return substring(#txt, #firstPos+len(#find)+1, #lastPos-#firstPos-len(#find)-1)
end
select dbo.FindValue('foo=abc;bar=def;baz=ghi', 'bar')
update: was not using the length of #find
this is assuming that the string will have the same string format just substitute the column name for the 'foo=abc;bar=def;baz=ghi'
select substring('foo=abc;bar=def;baz=ghi',patindex('%bar=%','foo=abc;bar=def;baz=ghi')+4, len('foo=abc;bar=def;baz=ghi')-patindex('%;baz=%','foo=abc;bar=def;baz=ghi')-4)
This can achieve in simple way
DECLARE #str VARCHAR(30)
DECLARE #start INT
SET #str='foo=abc;bar=def;baz=ghi'
SET #start=CHARINDEX('bar',#str)
PRINT SUBSTRING(#str,#start,3)

SQL Server 2005:charindex starting from the end

I have a string 'some.file.name',I want to grab 'some.file'.
To do that,I need to find the last occurrence of '.' in a string.
My solution is :
declare #someStr varchar(20)
declare #reversedStr varchar(20)
declare #index int
set #someStr = '001.002.003'
set #reversedStr = reverse(#someStr)
set #index = len(#someStr) - charindex('.',#reversedStr)
select left(#someStr,#index)
Well,isn't it too complicated?I was just intented to using 'some.file' in a where-clause.
Anyone has a good idea?
What do you need to do with it?? Do you need to grab the characters after the last occurence of a given delimiter?
If so: reverse the string and search using the normal CHARINDEX:
declare #test varchar(100)
set #test = 'some.file.name'
declare #reversed varchar(100)
set #reversed = REVERSE(#test)
select
REVERSE(SUBSTRING(#reversed, CHARINDEX('.', #reversed)+1, 100))
You'll get back "some.file" - the characters up to the last "." in the original file name.
There's no "LASTCHARINDEX" or anything like that in SQL Server directly. What you might consider doing in SQL Server 2005 and up is great a .NET extension library and deploy it as an assembly into SQL Server - T-SQL is not very strong with string manipulation, whereas .NET really is.
A very simple way is:
SELECT
RIGHT(#str, CHARINDEX('.', REVERSE(#str)) - 1)
This will also work:
DECLARE
#test VARCHAR(100)
SET #test = 'some.file.name'
SELECT
LEFT(#test, LEN(#test) - CHARINDEX('.', REVERSE(#test)))
Take one ')'
declare #test varchar(100)
set #test = 'some.file.name'
select left(#test,charindex('.',#test)+charindex('.',#test)-1)
CREATE FUNCTION [dbo].[Instr] (
-------------------------------------------------------------------------------------------------
-- Name: [dbo].[Instr]
-- Purpose: Find The Nth Value Within A String
-------------------------------------------------------------------------------------------------
-- Revisions:
-- 25-FEB-2011 - HESSR - Initial Revision
-------------------------------------------------------------------------------------------------
-- Parameters:
-- 1) #in_FindString - NVARCHAR(MAX) - INPUT - Input Find String
-- 2) #in_String - NVARCHAR(MAX) - INPUT - Input String
-- 3) #in_StartPos - SMALLINT - INPUT - Position In The String To Start Looking From
-- (If Start Position Is Negative, Search Begins At The End Of The String)
-- (Negative 1 Starts At End Position 1, Negative 3 Starts At End Position Minus 2)
-- 4) #in_Nth - SMALLINT - INPUT - Nth Occurrence To Find The Location For
-------------------------------------------------------------------------------------------------
-- Returns: SMALLINT - Position Of String Segment (Not Found = 0)
-------------------------------------------------------------------------------------------------
#in_FindString NVARCHAR(MAX),
#in_String NVARCHAR(MAX),
#in_StartPos SMALLINT = NULL,
#in_Nth SMALLINT = NULL
)
RETURNS SMALLINT
AS
BEGIN
DECLARE #loc_FindString NVARCHAR(MAX);
DECLARE #loc_String NVARCHAR(MAX);
DECLARE #loc_Position SMALLINT;
DECLARE #loc_StartPos SMALLINT;
DECLARE #loc_Nth SMALLINT;
DECLARE #loc_Idx SMALLINT;
DECLARE #loc_FindLength SMALLINT;
DECLARE #loc_Length SMALLINT;
SET #loc_FindString = #in_FindString;
SET #loc_String = #in_String;
SET #loc_Nth = ISNULL(ABS(#in_Nth), 1);
SET #loc_FindLength = LEN(#loc_FindString+N'.') - 1;
SET #loc_Length = LEN(#loc_String+N'.') - 1;
SET #loc_StartPos = ISNULL(#in_StartPos, 1);
SET #loc_Idx = 0;
IF (#loc_StartPos = ABS(#loc_StartPos))
BEGIN
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
END
ELSE
BEGIN
SET #loc_StartPos = ABS(#loc_StartPos);
SET #loc_FindString = REVERSE(#in_FindString);
SET #loc_String = REVERSE(#in_String);
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
IF (#loc_Position > 0)
SET #loc_Position = #loc_Length - #loc_Position + (1 - #loc_FindLength) + 1;
END;
RETURN (#loc_Position);
END;
GO
Here is a shorter version
DECLARE #someStr varchar(20)
set #someStr = '001.002.003'
SELECT REVERSE(Substring(REVERSE(#someStr),CHARINDEX('.', REVERSE(#someStr))+1,20))