Extract a number after a number pattern in SQL - sql-server

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.

Related

How to get substring in TSQL

I want to extract special word from a sentence in SQL Server.
For example I want to extract No-13 from 'Street3 NO-13 Floor 4th'
Following code is my primary code, but I can't find the last index to get special word:
SELECT PATINDEX('%Y[^][0-9]%', 'Street3 NO-13 Floor 4th')
Fortunately I found a solution, I use following code:
DECLARE #txt NVARCHAR(255)
SET #txt = 'Street3 NO- 13 Floor 4th'
DECLARE #startIndex INT
SELECT #startIndex = PATINDEX('% No%[0-9]%',#txt)
Declare #FirstLetters AS NVARCHAR(50)
DECLARE #remainingString NVARCHAR(MAX)
SELECT #remainingString = SUBSTRING(#txt, #startIndex, LEN(#txt) - #startIndex)
SELECT #FirstLetters=SUBSTRING(#remainingString, 0, PATINDEX('%[0-9]%',#remainingString))
SELECT #remainingString=REPLACE(#remainingString,#FirstLetters,'')
SELECT #FirstLetters +LEFT(
SubString(#remainingString, PatIndex('%[0-9.-]%', #remainingString), 8000),
PatIndex('%[^0-9.-]%', SubString(#remainingString, PatIndex('%[0-9.-]%',
#remainingString), 8000) + 'X')-1) AS BuildingNo
The length of the pattern is fixed, so you always know where the pattern ends. However, it seems that what you really want is to find the end of a word that starts with a given pattern. If you only care about spaces as word separators, this is quite simple - charindex takes an optional starting location index, so you can just find the first space after the patindex result. Then you can use substring to get the string between the two indices.

What is the encode(<columnName>, 'escape') PostgreSQL equivalent in SQL Server?

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

Format a numeric field as text with fixed pattern sql server 2008

I have a numeric field (field1) that has numeric values 1.2, 23.72, 14.02 etc.
I need to present this as a fixed text field format 13 characters as 000000000.000 e.g. 23.72 must display 000000023.720 (9 digits with 3 decimals)Server 2008
What is the best way to do this ?
You can use the following query:
SELECT FORMAT(ColumnName, '000000000.000') FROM TableName
I'm not saying this is the best way, as the final presentation layer (your webpage) might still render it as a numeric value that will follow the format defined on that layer.
You can use FORMAT(#input, '000000000.000') but that won't give you intended output for longer numbers.
You can make your own function which pads zeros ahead and otherwise stops your execution in case of longer numbers.
DECLARE #input NUMERIC(20,7);
DECLARE #number NUMERIC(12,3);
DECLARE #output VARCHAR(13)
SET #input = 123620;
SET #number = CONVERT(NUMERIC(12,3), #input)
SET #output = CONVERT(CHAR(13), #number)
SET #output = REPLICATE('0', 10 - CHARINDEX('.',#output)) + #output
try this,
Declare #i float=23.72
declare #j decimal(18,3)=#i
select #j
select replicate('0',13-len(#j))+cast(#j as varchar)
and tell that for which data it do not work.
Or try this one
SELECT LEFT(RIGHT(REPLICATE('0',12) + CAST('23.72' AS VARCHAR(10)),12) + REPLICATE('0',3),13)
output
000000023.720

T-SQL Find length of word within a string

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.

Extracting month using substring in sql server

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)

Resources