Please help me get the substring of the following text.
I would like to be able to extract the text
PilotCube_2Year
FROM
/content/folder[#name='Reporting Packages']/package[#name='PiotCube_2Year']
I am using SQL Server 2008
I have tried substring and Charindex but could not really get the string PilotCube_2Year
Assuming package[#name= is what tells you where the string you are looking for is, you could try something like this:
DECLARE #toSearch AS VARCHAR(100) = '/content/folder[#name=''Reporting Packages'']/package[#name=''PiotCube_2Year'']'
DECLARE #toFind AS VARCHAR(100) = 'package[#name='
DECLARE #start AS INT = CHARINDEX(#toFind , #toSearch ) + LEN(#toFind) + 1
SELECT SUBSTRING(#toSearch, --expression
#start, --start
CHARINDEX(']' , #toSearch, #start) - #start - 1) --length
Result
PiotCube_2Year
Related
I am looking for a function that selects English numbers and letters only:
Example:
TEKA תנור ביל דין in HLB-840 P-WH לבן
I want to run a function and get the following result:
TEKA HLB-840 P-WH
I'm using MS SQL Server 2012
What you really need here is regex replacement, which SQL Server does not support. Broadly speaking, you would want to find [^A-Za-z0-9 -]+\s* and then replace with empty string. Here is a demo showing that this works as expected:
Demo
This would output TEKA in HLB-840 P-WH for the input you provided. You might be able to do this in SQL Server using a regex package or UDF. Or, you could do this replacement outside of SQL using any number of tools which support regex (e.g. C#).
SQL-Server is not the right tool for this.
The following might work for you, but there is no guarantee:
declare #yourString NVARCHAR(MAX)=N'TEKA תנור ביל דין in HLB-840 P-WH לבן';
SELECT REPLACE(REPLACE(REPLACE(REPLACE(CAST(#yourString AS VARCHAR(MAX)),'?',''),' ','|~'),'~|',''),'|~',' ');
The idea in short:
A cast of NVARCHAR to VARCHAR will return all characters in your string, which are not known in the given collation, as question marks. The rest is replacements of question marks and multi-blanks.
If your string can include a questionmark, you can replace it first to a non-used character, which you re-replace at the end.
If you string might include either | or ~ you should use other characters for the replacements of multi-blanks.
You can influence this approach by specifying a specific collation, if some characters pass by...
there is no build in function for such purpose, but you can create your own function, should be something like this:
--create function (split string, and concatenate required)
CREATE FUNCTION dbo.CleanStringZZZ ( #string VARCHAR(100))
RETURNS VARCHAR(100)
BEGIN
DECLARE #B VARCHAR(100) = '';
WITH t --recursive part to create sequence 1,2,3... but will better to use existing table with index
AS
(
SELECT n = 1
UNION ALL
SELECT n = n+1 --
FROM t
WHERE n <= LEN(#string)
)
SELECT #B = #B+SUBSTRING(#string, t.n, 1)
FROM t
WHERE SUBSTRING(#string, t.n, 1) != '?' --this is just an example...
--WHERE ASCII(SUBSTRING(#string, t.n, 1)) BETWEEN 32 AND 127 --you can use something like this
ORDER BY t.n;
RETURN #B;
END;
and then you can use this function in your select statement:
SELECT dbo.CleanStringZZZ('TEKA תנור ביל דין in HLB-840 P-WH לבן');
create function dbo.AlphaNumericOnly(#string varchar(max))
returns varchar(max)
begin
While PatIndex('%[^a-z0-9]%', #string) > 0
Set #string = Stuff(#string, PatIndex('%[^a-z0-9]%', #string), 1, '')
return #string
end
In the same vein as this question, what is the equivalent in SQL Server to the following Postgres statement?
select encode(some_field, 'escape') from only some_table
As you were told already, SQL-Server is not the best with such issues.
The most important advise to avoid such issues is: Use the appropriate data type to store your values. Storing binary data as a HEX-string is running against this best practice. But there are some workarounds:
I use the HEX-string taken from the linked question:
DECLARE #str VARCHAR(100)='0x61736461640061736461736400';
--here I use dynamically created SQL to get the HEX-string as a real binary:
DECLARE #convBin VARBINARY(MAX);
DECLARE #cmd NVARCHAR(MAX)=N'SELECT #bin=' + #str;
EXEC sp_executeSql #cmd
,N'#bin VARBINARY(MAX) OUTPUT'
,#bin=#convBin OUTPUT;
--This real binary can be converted to a VARCHAR(MAX).
--Be aware, that in this case the input contains 00 as this is an array.
--It is possible to split the input at the 00s, but this is going to far...
SELECT #convBin AS HexStringAsRealBinary
,CAST(#convBin AS VARCHAR(MAX)) AS CastedToString; --You will see the first "asda" only
--If your HEX-string is not longer than 10 bytes there is an undocumented function:
--You'll see, that the final AA is cut away, while a shorter string would be filled with zeros.
SELECT sys.fn_cdc_hexstrtobin('0x00112233445566778899AA')
SELECT CAST(sys.fn_cdc_hexstrtobin(#str) AS VARCHAR(100));
UPDATE: An inlinable approach
The following recursive CTE will read the HEX-string character by character.
Furthermore it will group the result and return two rows in this case.
This solution is very specific to the given input.
DECLARE #str VARCHAR(100)='0x61736461640061736461736400';
WITH recCTE AS
(
SELECT 1 AS position
,1 AS GroupingKey
,SUBSTRING(#str,3,2) AS HEXCode
,CHAR(SUBSTRING(sys.fn_cdc_hexstrtobin('0x' + SUBSTRING(#str,3,2)),1,1)) AS TheLetter
UNION ALL
SELECT r.position+1
,r.GroupingKey + CASE WHEN SUBSTRING(#str,2+(r.position)*2+1,2)='00' THEN 1 ELSE 0 END
,SUBSTRING(#str,2+(r.position)*2+1,2)
,CHAR(SUBSTRING(sys.fn_cdc_hexstrtobin('0x' + SUBSTRING(#str,2+(r.position)*2+1,2)),1,1)) AS TheLetter
FROM recCTE r
WHERE position<LEN(#str)/2
)
SELECT r.GroupingKey
,(
SELECT x.TheLetter AS [*]
FROM recCTE x
WHERE x.GroupingKey=r.GroupingKey
AND x.HEXCode<>'00'
AND LEN(x.HEXCode)>0
ORDER BY x.position
FOR XML PATH(''),TYPE
).value('.','varchar(max)')
FROM recCTE r
GROUP BY r.GroupingKey;
The result
1 asdad
2 asdasd
Hint: Starting with SQL Server 2017 there is STRING_AGG(), which would reduce the final SELECT...
If you need this functionality, it's going to be up to you to implement it. Assuming you just need the escape variant, you can try to implement it as a T-SQL UDF. But pulling strings apart, working character by character and building up a new string just isn't a T-SQL strength. You'd be looking at a WHILE loop to count over the length of the input byte length, SUBSTRING to extract the individual bytes, and CHAR to directly convert the bytes that don't need to be octal encoded.1
If you're going to start down this route (and especially if you want to support the other formats), I'd be looking at using the CLR support in SQL Server, to create the function in a .NET language (C# usually preferred) and use the richer string manipulation functionality there.
Both of the above assume that what you're really wanting is to replicate the escape format of encode. If you just want "take this binary data and give me a safe string to represent it", just use CONVERT to get the binary hex encoded.
1Here's my attempt at it. I'd suggest a lot of testing and tweaking before you use it in anger:
create function Postgresql_encode_escape (#input varbinary(max))
returns varchar(max)
as
begin
declare #i int
declare #len int
declare #out varchar(max)
declare #chr int
select #i = 1, #out = '',#len = DATALENGTH(#input)
while #i <= #len
begin
set #chr = SUBSTRING(#input,#i,1)
if #chr > 31 and #chr < 128
begin
set #out = #out + CHAR(#chr)
end
else
begin
set #out = #out + '\' +
RIGHT('000' + CONVERT(varchar(3),
(#chr / 64)*100 +
((#chr / 8)%8)*10 +
(#chr % 8))
,3)
end
set #i = #i + 1
end
return #out
end
I am working in SQL server. I have some number like 130-0029. I need to get the integer after the - delimiter out of it. So in this example I need to return 29. These are the following scenarios I have with this,
The pattern may differ like 130-00000029 or 130-0029.
If there are all 0's then print 0, else get actual number like 29.
Please advise/suggest me on this.
Here is an example:
declare #s varchar(100) = '130-0029'
select cast(substring(#s, patindex('%[-]%', #s) + 1, len(#s)) as int)
You may need to cast to some numeric if the number overflows ineteger type.
Try this:
DECLARE #num varchar(50) = '130-0029'
SELECT CAST(SUBSTRING(#num, CHARINDEX('-', #num) + 1, LEN(#num)) AS INT)
Here is a fiddle.
This also works if the - is missing. But if what follows is not a number it will give an error.
declare #string as varchar(100)
set #string = '130-0029'
select convert(int,Right(#string, LEN(#string)-CHARINDEX('-', #string)))
Probably not so different than other answers, but this works using STUFF too:
DECLARE #String VARCHAR(10) = '130-0029';
SELECT CONVERT(INT, STUFF(#String, 1, CHARINDEX('-', #String), ''));
See this running in Query Stack Exchange.
With PATINDEX I can find the first occourence of a pattern in a string, say a number - in the string there is several matches to my pattern
My question is how can I find the end position of the first occourence of that pattern in a string?
DECLARE #txt VARCHAR(255)
SET #txt = 'this is a string 30486240 and the string is still going 30485 and this is the end'
PRINT SUBSTRING(#txt,PATINDEX('%[0-9]%',#txt),8)
My problem is, I dont want to put in the 8 in manually, I want to find the length of the first number
Using SQL Server 2012
Try this, it should return the first number from your text:
DECLARE #txt VARCHAR(255)
SET #txt = 'this is a string 30486240 and the string is still going 30485 and this is the end'
DECLARE #startIndex INTEGER
SELECT #startIndex = PATINDEX('%[0-9]%',#txt)
DECLARE #remainingString NVARCHAR(MAX)
SELECT #remainingString = substring(#txt, #startIndex, LEN(#txt) - #startIndex)
DECLARE #endingIndex INTEGER
SELECT #endingIndex = PATINDEX('%[a-zA-Z]%', #remainingString) - 1
SELECT RTRIM(SUBSTRING(#txt, #startIndex, #endingIndex))
This query will work as long as you don't have letters "embedded" in your numbers, like 30486a24b0
Here is one solution when you don't know the length of the substring:
SELECT Left(
SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000),
PatIndex('%[^0-9.-]%', SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000) + 'X')-1)
Source: http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/extracting-numbers-with-sql-server/
I had to run through the exercise multiple times and kept thinking the blog post was wrong, before noticing the caret in the second PATINDEX.
I have the following code
#FiscalMonth As varchar(MAX) ='[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[4]&[1]'
In my case the month will be 10 . I have tried the following code
SET #FiscalMonthNumber = cast(substring(right(#FiscalMonth,18),1,2) as nvarchar(max))
The code above works fine but when I have
#FiscalMonth As varchar(MAX) ='[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[11]&[1]'
I have as result 0] which is incorrect .
Ugh. This assumes that the first time you encounter a pattern like '[n' (where n is any number, and it will occur within the first 8000 characters of the string), that is the month:
DECLARE #fm VARCHAR(MAX);
SET #fm = '[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[4]&[1]';
SELECT SUBSTRING(#fm, PATINDEX('%[[][0-9]%', #fm) + 1,
CHARINDEX(']', SUBSTRING(#fm, PATINDEX('%[[][0-9]%', #fm) + 1, 8000)) - 1);
Result:
----------
10
If there are other possible patterns or edge cases, make them known.
SQLfiddle demo
I have checked your code it is working fine it is showing 10 in both cases maybe you need to look into you logic.
DECLARE #FiscalMonth varchar(MAX) ='[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[4]&[1]'
DECLARE #FiscalMonthNumber nvarchar(max) = cast(substring(right(#FiscalMonth,18),1,2) as nvarchar(max))
SELECT #FiscalMonthNumber
DECLARE #FiscalMonth1 As varchar(MAX) ='[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[4]&[1]'
DECLARE #FiscalMonthNumber1 AS nvarchar(max) = cast(substring(right(#FiscalMonth,18),1,2) as nvarchar(max))
SELECT #FiscalMonthNumber1
Or you can extract all the numbers from you string and then extract the month number from your number string. something like this
DECLARE #FiscalMonth1 As varchar(MAX) ='[Dim Date].[Fiscal].[Fiscal Month Number].&[10]&[2014]&[4]&[1]'
WHILE PATINDEX('%[^0-9]%',#FiscalMonth1) <> 0
SET #FiscalMonth1 = STUFF(#FiscalMonth1,PATINDEX('%[^0-9]%',#FiscalMonth1),1,'')
SELECT LEFT(#FiscalMonth1, 2)