How to count string between string in sql - sql

I have a data that having different length of value.
For example I have 2 rows of data:
CL-CI/PST/102/VII/2016
CL-CI/PST/0102/VII/2016
The difference between them is 102 (3 digits) and 0102 (4 digits)
I want in my SQL checking:
if (3Digits)
begin
....
end
else
begin
....
end
The records of data format is not fixed. Just not fixed on this string VII/2016 (based on month in roman numerals/year).
I know how to count the string is using LEN. But my problem is when I select top 1 of data. In this top 1 data that I got, I want to check dynamically if it is 4 digits / 3 digits that I got from that top 1. I'm stuck on this.

Try it like this
Easy: Just the length
DECLARE #s VARCHAR(100)='CL-CI/PST/0102/VII/2016';
SELECT LEN(CAST('<x>' + REPLACE(#s,'/','</x><x>')+'</x>' AS XML).value('/x[3]','varchar(max)'))
The result is 4
setbased approach
DECLARE #tbl TABLE(ID INT IDENTITY,YourString VARCHAR(100),OtherValue VARCHAR(100));
INSERT INTO #tbl(YourString,OtherValue) VALUES
('CL-CI/PST/102/VII/2016','With 3 digits')
,('CL-CI/PST/0102/VII/2016','With 4 digits');
WITH ExtendByPart3 AS
(
SELECT *
,CAST('<x>' + REPLACE(YourString,'/','</x><x>')+'</x>' AS XML).value('/x[3]','varchar(max)') AS Part3
FROM #tbl
)
SELECT *,LEN(Part3) AS LenPart3 FROM ExtendByPart3
The result
ID YourString OtherValue Part3 LenPart3
1 CL-CI/PST/102/VII/2016 With 3 digits 102 3
2 CL-CI/PST/0102/VII/2016 With 4 digits 0102 4
Btw: There are several questions about: How to access item X of a seperated string and most answers come with very complex CTEs, loops, CLR methods... This approach is direct and type safe. Change the nvarchar(max) of the .value() function to int and you would get the number - if needed.
I placed an answer to one of these questions myself, but - as this question is existing for years - the leading answers are very old fashioned and - IMO - outdated. But still it migth be worth reading this...
Retrieve all values
If you might be interested in your other values too, you could do this:
DECLARE #tbl TABLE(ID INT IDENTITY,YourString VARCHAR(100),OtherValue VARCHAR(100));
INSERT INTO #tbl(YourString,OtherValue) VALUES
('CL-CI/PST/102/VII/2016','With 3 digits')
,('CL-CI/PST/0102/VII/2016','With 4 digits');
WITH Splitted AS
(
SELECT CAST('<x>' + REPLACE(YourString,'/','</x><x>')+'</x>' AS XML) AS XMLData
FROM #tbl
)
SELECT XMLData.value('/x[1]','varchar(max)') AS Part1
,XMLData.value('/x[2]','varchar(max)') AS Part2
,XMLData.value('/x[3]','int') AS Number
,XMLData.value('/x[4]','varchar(max)') AS MonthRoman
,XMLData.value('/x[5]','int') AS TheYear
FROM Splitted
The result (attention: as returned as int the Number is without the leading zero)
Part1 Part2 Number MonthRoman TheYear
CL-CI PST 102 VII 2016
CL-CI PST 102 VII 2016

Perhaps case and like are sufficient:
select (case when col like '%/%/[0-9][0-9][0-9]/%' then <3 digit stuff>
when col like '%/%/[0-9][0-9][0-9][0-9]/%' then <4 digit stuff>
end)

Related

Filter IDs with just numbers excluding letters

So I have results that begins with 2 letters followed by 3 numbers, for example:
ID_Sample
AB001
BC003
AB100
BC400
How can I do a query that ignores the letters and just looks up the numbers to do a filter? For example:
WHERE ID_Sample >= 100
I tried using a "Replace" to get rid of known letters, but I figured there might be a better way. For example:
Select
Replace(id_sample,'AB','')
Choosing the 3 numerals on the right would work too.
For your sample data, you can just start at the third character and convert to a number:
where try_convert(int, stuff(ID_Sample, 1, 2, '')) > 100
Or, if you know that the number is 3 characters:
where try_convert(int, right(ID_Sample, 3)) > 100
+1 for Gordon's answer. This is a fun problem that you can solve using TRANSLATE if you're using SQL 2017+.
First, in case you've never used it, Per BOL TRANSLATE:
Returns the string provided as a first argument after some characters
specified in the second argument are translated into a destination set
of characters specified in the third argument.2
This:
SELECT TRANSLATE('123AABBCC!!!','ABC','XYZ');
Returns: 123XXYYZZ!!!
Here's the solution using TRANSLATE:
-- Sample Data
DECLARE #t TABLE (ID_Sample CHAR(6))
INSERT #t (ID_Sample) VALUES ('AB001'),('BC003'),('AB100'),('BC400'),('CC555');
-- Solution
SELECT
ID_Sample = t.ID_Sample,
ID_Sample_Int = s.NewString
FROM #t AS t
CROSS JOIN (VALUES('ABCDEFGHIJKLMNOPQRSTUVWXYZ', REPLICATE(0,26))) AS f(S1,S2)
CROSS APPLY (VALUES(TRY_CAST(TRANSLATE(t.ID_Sample,f.S1,f.S2) AS INT))) AS s(NewString)
WHERE s.NewString >= 100;
Without the WHERE clause filter you get:
ID_Sample ID_Sample_Int
--------- -------------
AB001 1
BC003 3
AB100 100
BC400 400
CC555 555
... the WHERE clause filters out the first two rows.
Check these methods- Unit test also done!
Declare #Table as table(ID_Sample varchar(20))
set nocount on
Insert into #Table (ID_Sample)
Values('AB001'),('BC003'),('AB100'),('BC400')
--substring_method
select * from #Table
where try_cast(substring(ID_Sample,3,3) as int) >100
--right_method
select * from #Table
where try_cast(right(ID_Sample,3) as int) >100
--stuff_method
select * from #Table
where try_cast(stuff(ID_Sample,1,2,'') as int) >100
--replace_method
select * from #Table
where try_cast(replace(ID_Sample,left(ID_Sample,2),'') as int) >100

sql extract rightmost number in string and increment

i have transaction codes like
"A0004", "1B2005","20CCCCCCC21"
I need to extract the rightmost number and increment the transaction code by one
"AA0004"----->"AA0005"
"1B2005"------->"1B2006"
"20CCCCCCCC21"------>"20CCCCCCCC22"
in SQL Server 2012.
unknown length of string
right(n?) always number
dealing with unsignificant number of string and number length is out of my league.
some logic is always missing.
LEFT(#a,2)+RIGHT('000'+CONVERT(NVARCHAR,CONVERT(INT,SUBSTRING( SUBSTRING(#a,2,4),2,3))+1)),3
First, I want to be clear about this: I totally agree with the comments to the question from a_horse_with_no_name and Jeroen Mostert.
You should be storing one data point per column, period.
Having said that, I do realize that a lot of times the database structure can't be changed - so here's one possible way to get that calculation for you.
First, create and populate sample table (Please save us this step in your future questions):
DECLARE #T AS TABLE
(
col varchar(100)
);
INSERT INTO #T (col) VALUES
('A0004'),
('1B2005'),
('1B2000'),
('1B00'),
('20CCCCCCC21');
(I've added a couple of strings as edge cases you didn't mention in the question)
Then, using a couple of cross apply to minimize code repetition, I came up with that:
SELECT col,
LEFT(col, LEN(col) - LastCharIndex + 1) +
REPLICATE('0', LEN(NumberString) - LEN(CAST(NumberString as int))) +
CAST((CAST(NumberString as int) + 1) as varchar(100)) As Result
FROM #T
CROSS APPLY
(
SELECT PATINDEX('%[^0-9]%', Reverse(col)) As LastCharIndex
) As Idx
CROSS APPLY
(
SELECT RIGHT(col, LastCharIndex - 1) As NumberString
) As NS
Results:
col Result
A0004 A0005
1B2005 1B2006
1B2000 1B2001
1B00 1B01
20CCCCCCC21 20CCCCCCC22
The LastCharIndex represents the index of the last non-digit char in the string.
The NumberString represents the number to increment, as a string (to preserve the leading zeroes if they exists).
From there, it's simply taking the left part of the string (that is, up until the number), and concatenate it to a newly calculated number string, using Replicate to pad the result of addition with the exact number of leading zeroes the original number string had.
Try This
DECLARE #test nvarchar(1000) ='"A0004", "1B2005","20CCCCCCC21"'
DECLARE #Temp AS TABLE (ID INT IDENTITY,Data nvarchar(1000))
INSERT INTO #Temp
SELECT #test
;WITH CTE
AS
(
SELECT Id,LTRIM(RTRIM((REPLACE(Split.a.value('.' ,' nvarchar(max)'),'"','')))) AS Data
,RIGHT(LTRIM(RTRIM((REPLACE(Split.a.value('.' ,' nvarchar(max)'),'"','')))),1)+1 AS ReqData
FROM
(
SELECT ID,
CAST ('<S>'+REPLACE(Data,',','</S><S>')+'</S>' AS XML) AS Data
FROM #Temp
) AS A
CROSS APPLY Data.nodes ('S') AS Split(a)
)
SELECT CONCAT('"'+Data+'"','-------->','"'+CONCAT(LEFT(Data,LEN(Data)-1),CAST(ReqData AS VARCHAR))+'"') AS ExpectedResult
FROM CTE
Result
ExpectedResult
-----------------
"A0004"-------->"A0005"
"1B2005"-------->"1B2006"
"20CCCCCCC21"-------->"20CCCCCCC22"
STUFF(#X
,LEN(#X)-CASE PATINDEX('%[A-Z]%',REVERSE(#X)) WHEN 0 THEN LEN(#X) ELSE PATINDEX('%[A-Z]%',REVERSE(#X))-1 END+1
,LEN(((RIGHT(#X,CASE PATINDEX('%[A-Z]%',REVERSE(#X)) WHEN 0 THEN LEN(#X) ELSE PATINDEX('%[A-Z]%',REVERSE(#X))-1 END)/#N)+1)#N)
,((RIGHT(#X,CASE PATINDEX('%[A-Z]%',REVERSE(#X)) WHEN 0 THEN LEN(#X) ELSE PATINDEX('%[A-Z]%',REVERSE(#X))-1 END)/#N)+1)#N)
works on number only strings
99 becomes 100
mod(#N) increments

Query to pad left of a field with 0's [duplicate]

This question already has answers here:
Formatting Numbers by padding with leading zeros in SQL Server
(14 answers)
Closed 7 years ago.
I have been working on a query (in sql Server TSQL) which fills left of a number with 0's so output is always 5 digit.
So:
Select MuNumber From Mytable
for data 11,011,2132,1111
Creates output like
00011
02134
01111
I tried Lpad Function but numer of 0's can be different.
if Munumber is 1 we need 0000 and If MyNumber is 34 we need 000
Assuming that MuNumber is VARCHAR simply use RIGHT
SELECT RIGHT('00000' + MuNumber, 5)
FROM Mytable
Otherwise you need to convert it first
SELECT RIGHT('00000' + CONVERT(VARCHAR(5), MuNumber), 5)
FROM Mytable
And in general you can use this pattern:
DECLARE #num INT = 10;
SELECT RIGHT(REPLICATE('0', #num) + CONVERT(VARCHAR(5), MuNumber), #num)
FROM Mytable
Try this
select right('00000'+cast(col as varchar(5)),5) from table
You can use the user defined function udfLeftSQLPadding where you can find the source codes at SQL Pad Leading Zeros
After you create the function on your database, you can use it as follows
select
dbo.udfLeftSQLPadding(MuNumber,5,'0')
from dbo.Mytable
Another option:
declare #n int = 6
select stuff(replicate('0', #n), 6-len(n), len(n), n)
from (values('123'), ('2493'), ('35')) as x(n)

Select Part of Column

I was wondering if anyone could help with a query to select part of a column.
The column 'criteriadata' contains data that would look like this:
CriteriaData
14 27 15 C
14 30 15 DD
14 38 15 Pass
14 33 15 Pass
How can I select just the data that appears after the number 15.
Many thanks.
SELECT RIGHT(CriteriaData,
LEN(CriteriaData) - CHARINDEX('15', CriteriaData, 1) - 2)
FROM TableName
WHERE CriteriaData LIKE '%15%';
SQL Fiddle Demo
declare #T table
(
CriteriaData varchar(20)
)
insert into #T values
('14 27 15 C'),
('14 30 15 DD'),
('14 38 15 Pass'),
('14 33 15 Pass')
select stuff(CriteriaData, 1, 3+charindex(' 15 ', CriteriaData), '')
from #T
Result:
---------
C
DD
Pass
Pass
If CriteriaCData always contains a pattern of 3 numbers of 2 numerics separated by a space then you always want to retrieve from 10th chars:
select SUBSTR(CriteriaCData, 10) from xxx
If you are under oracle min 10.g then use REGEXP_SUBSTR to retrieve the alpha pattern
SELECT upper(REGEXP_SUBSTR(CriteriaCData, '[a-zA-Z]*$')) FROM xxx
Since you seem to want everything from the ninth character onwards, you could use RIGHT and LEN
SELECT right([CriteriaData], len([CriteriaData]) - 9)
However, you'd be better off normalizing your data so it was already in a seperate column.
On oracle use LENGTH instead of LEN
SELECT substr(CriteriaData, 8, LENGTH(CriteriaData) - 9) from table
You should use substring with left functions
Have a look at this: How to extract this specific substring in SQL Server?
And this: http://msdn.microsoft.com/en-us/library/aa259342(v=sql.80).aspx
SELECT substring(criteriadata, 9, LEN(criteriadata)-8) from table
This assumes that the position of 15 is fixed.
Declare #x nvarchar(100) = '14 30 15 DD';
Select substring(#x, (select charindex('15',#x,1) + 2) ,len(#x));
I created a SQL function to split the criteria by the spaces and used the last remaining value after the last space.
create function dbo.getCriteria
(
#criteria varchar(500)
)
returns varchar(500)
begin
declare #space as int
select #space=charindex(' ', data) from mydata
while #space > 0
begin
set #criteria=substring(#criteria, #space + 1, len(#criteria))
select #space=charindex(' ', #criteria)
end
return #criteria
end
select dbo.getCriteria(data) from mydata
SELECT
RIGHT(CriteriaData, LEN(CriteriaData) - (CHARINDEX('15', CriteriaData, 1) - 2))
FROM
MyTable;
As I had trouble making prior answers work, I had to find my own and figure for future reference I'd leave it on Stack Overflow. My field has XML but it's an NVarchar field and should generalise just fine - if you have a clear criteria for left AND right surrounding strings.
It's not a complete match to this question but I hope it helps someone else who has huge strings in their columns and needs to snip out a string that varies in between two others!
WITH r
AS (
SELECT TOP 100 RIGHT(XMLData, LEN(XMLData)-CHARINDEX('<INVOICE_NO>', XMLData)-11) AS xmldata
FROM IncomingPartsInvoiceXML)
SELECT LEFT(xmldata, CHARINDEX('<\/INVOICE_NO>', XMLData)-1)
FROM r;

String parsing in SQL Server

I have string column email_id; the data will look like this:
email_id
"1"
"6"
"3 4"
"8"
"0 3"
"0 5 7"
I want to get list of ids as integer. If I have two numbers in my string, I want the last one. My result should look like;
SELECT some_function (email_id ) FROM table
1
6
4
8
3
7
Is it possible to do this in SQL Server?
SELECT
CAST(RIGHT(email_id, LEN(email_id) - CHARINDEX(' ', email_id)) AS INT)
FROM
yourTable
IF and ONLY IF, all your values can reliably be cast to an INT, and there is only ever one space at most.
EDIT To deal with a list of n values
This isn't pretty, but it avoid recurrsion and/or loops. If someone gives an answer without REVERSE() test to see if it's faster than this or not.
SELECT
CAST(
REVERSE(
LEFT(
REVERSE(email_id),
CHARINDEX(' ', REVERSE(email_id) + ' ') - 1
)
)
AS INT
)
FROM
yourTable
SELECT CAST(replace(your_column ,' ','') as int) FROM table