I have a column which has inconsistent data. The column named ID and it can have values such as
0897546321
ABC,0876455321
ABC,XYZ,0873647773
ABC,
99756
test only
The SQL query should fetch only Ids which are of 10 digit in length, should begin with a 08 , should be not null and should not contain all characters. And for those values, which have both digits and characters such as ABC,XYZ,0873647773, it should only fetch the 0873647773 . In these kind of values, nothing is fixed, in place of ABC, XYZ , it can be anything and can be of any length.
The column Id is of varchar type.
My try: I tried the following query
select id
from table
where id is not null
and id not like '%[^0-9]%'
and id like '[08]%[0-9]'
and len(id)=10
I am still not sure how should I deal with values like ABC,XYZ,0873647773
P.S - I have no control over the database. I can't change its values.
SQL Server generally has poor support regular expressions, but in this case a judicious use of PATINDEX is viable:
SELECT SUBSTRING(id, PATINDEX('%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%', ',' + id + ','), 10) AS number
FROM yourTable
WHERE ',' + id + ',' LIKE '%,08[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9],%';
Demo
If you normalise your data, and split the delimited data into parts, you can achieve this some what more easily:
SELECT SS.value
FROM dbo.YourTable YT
CROSS APPLY STRING_SPLIT(YT.YourColumn,',') SS
WHERE LEN(SS.value) = 10
AND SS.value NOT LIKE '%[^0-9]%';
If you're on an older version of SQL Server, you'll have to use an alternative String Splitter method (such as a XML splitter or user defined inline table-value function); there are plenty of examples on these already on Stack Overflow.
db<>fiddle
Related
Here I want to store the value '202202171100DF' Which is coming after the first occurrence of ZZ.
DECLARE #Element1 VARCHAR(100)='DO#0000000000#ZZ#202202171100DF#ZZ#1#ZZ#20122877GH'
Below query will get the all values after the first occurrence of ZZ. I just want, it should get the first occurrence of ZZ. i.e.'202202171100DF'
SELECT SUBSTRING(#Element1,CHARINDEX('ZZ',#Element1)+3,len(#Element1));
As I mentioned in the comments, this really isn't a task for T-SQL. It has poor string manipulation functionality. There are a couple of methods you could use, though.
The first is similar to the method you attempted, using SUBSTRING and CHARINDEX:
DECLARE #ELEMENT1 VARCHAR(100)='DO#0000000000#ZZ#202202171100DF#ZZ#1#ZZ#20122877GH';
SELECT SUBSTRING(#ELEMENT1, CHARINDEX('ZZ#', #ELEMENT1) + 3, CHARINDEX('#', #ELEMENT1 + '#',CHARINDEX('ZZ#', #ELEMENT1) + 3) - (CHARINDEX('ZZ#', #ELEMENT1) + 3));
This is pretty messy, with all the references to CHARINDEX, but does get the job done.
Another method is the split the string into parts and then return the first row where the "identifier" has the value 'ZZ'. Unfortunately (hopefully until SQL Server 2022) SQL Server's in-built string splitter, STRING_SPLIT doesn't return the ordinal position, so we'll need to use something else such as a JSON splitter. Then you can use a pivot to match the identifier to the value and then get the "first" entry:
DECLARE #ELEMENT1 VARCHAR(100)='DO#0000000000#ZZ#202202171100DF#ZZ#1#ZZ#20122877GH';
WITH Identities AS(
SELECT [key] / 2 AS Entry,
MAX(CASE WHEN [key] % 2 = 0 THEN [Value] END) AS [Identity],
MAX(CASE WHEN [key] % 2 = 1 THEN [Value] END) AS [Value]
FROM OPENJSON(CONCAT('["',REPLACE(#ELEMENT1,'#', '","'),'"]')) OJ
GROUP BY [key] / 2)
SELECT TOP (1)
[Value]
FROM Identities
WHERE [Identity] = 'ZZ'
ORDER BY Entry ASC;
But, again, ideally do this out of T-SQL. If you need to send such data to SQL Server, do so in a normalised format or in properly defined JSON or XML, which SQL Server can natively consume (in all fully supported versions).
I have below records
Id Title
500006 FS/97/98/037
500007 FS/97/04/035
500008 FS/97/01/036
500009 FS/97/104/040
I should split Title field and get 4th part of text and return maximum value. In this example my query should return 040 or 40.
select max(cast(right(Title, charindex('/', reverse(Title) + '/') - 1) as int))
from your_table
SQLFiddle demo
You can use PARSENAME function since you always have 4 parts(confirmed in comments section)
select max(cast(parsename(replace(Title,'/','.'),1) as int))
from yourtable
If you want to split the data in the Title column and get the part from the splitted text by position, you may try with one JSON-based approach with a simple string transformation. You need to transform the data in the Title column into a valid JSON array (FS/97/98/037 into ["FS","97","08","037"]) and after that to parse thе data with OPENJSON(). The result from OPENJSON() (using default schema and parsing JSON array) is a table with columns key, value and type, and the key column holds the index of the items in the JSON array:
Note, that using STRING_SPLIT() is not an option here, because the order of the returned rows is not guaranteed.
Table:
CREATE TABLE Data (
Id varchar(6),
Title varchar(50)
)
INSERT INTO Data
(Id, Title)
VALUES
('500006', 'FS/97/98/037'),
('500007', 'FS/97/04/035'),
('500008', 'FS/97/01/036'),
('500009', 'FS/97/104/040')
Statement:
SELECT MAX(j.[value])
FROM Data d
CROSS APPLY OPENJSON(CONCAT('["', REPLACE(d.Title, '/', '","'), '"]')) j
WHERE (j.[key] + 1) = 4
If you data has fixed format with 4 parts, even this approach may help:
SELECT MAX(PARSENAME(REPLACE(Title, '/', '.'), 1))
FROM Data
You can also try the below query.
SELECT Top 1
CAST('<x>' + REPLACE(Title,'/','</x><x>') + '</x>' AS XML).value('/x[4]','int') as Value
from Data
order by 1 desc
You can find the live demo Here.
I'm using this code
(SELECT (MAX(CODE) +1 WHERE ISNUMERIC([code]) = 1)
I want to max +1 only my numbers of my column preventing characters characters.
NOTE: THIS QUESTION WAS TAGGED MYSQL WHEN THIS ANSWER WAS POSTED.
You can use substring_index() to split the values and then re-unite them:
(SELECT CONCAT(SUBSTRING_INDEX(MAX(Code), '-', 1), '-',
SUBSTRING_INDEX(MAX(CODE), '-', -1) + 1
)
FROM . . .
WHERE code LIKE '%NEW-1%'
)
This assumes that the wildcards do not have hyphens in them, and that the values after the "1" are all numbers.
Also, this doesn't pad the number is zeroes, but that is a good idea for such codes -- it ensures that they are always the same length and that they sort correctly.
The MAX() function accepts expressions, not just column names:
SELECT MAX(CASE ISNUMERIC(code) WHEN 1 THEN code END)+1 as next_code
FROM (
SELECT '15' AS code
UNION ALL SELECT ' 98 ' AS code
UNION ALL SELECT 'New-45' AS code
) foo
WHERE ISNUMERIC(code)=1;
16
(Link is to SQL Server 2005, docs for SQL Server 2000 are apparently no longer on line, but MAX() belongs to SQL standard anyway.)
I need to identify repeated numbers( Eg: 1111, 33333333, 5555555555,777777777 etc.) in a column.
How can I do this in sql server without having to hard code every scenario. The max length is 10 of the column. Any help is appreciated.
This will check if the column has all the same value in it.
SELECT *
FROM tablename
WHERE columnname = REPLICATE(LEFT(columnname,1),LEN(columnname))
As Nicholas Cary notes, if the column is numbers you'd need to cast as varchar first:
SELECT *
FROM tablename
WHERE CAST(columnname AS VARCHAR(10)) = REPLICATE(LEFT(CAST(columnname AS VARCHAR(10)),1),LEN(CAST(columnname AS VARCHAR(10))))
Riffing on #Dave.Gugg's excellent answer, here's another way, using patindex() to look for a character different than the first.
select *
from some_table t
where 0 = patindex( '[^' + left(t.some_column,1) + ']' , t.some_column )
Again, this only works for string types (char,varchar, etc.). Numeric types such as int will need to be converted first.
I am trying to query a mysql table which contains strings of numbers
(i.e. '1,2,3,4,5').
How do I search to see if it has '1' but not '11' bearing in mind if it is '9,10' '9%' doesnt work??
Fixed!
(field like '10' OR field like '%,10,%' OR field like '%,10' OR field like '10,%')
You could try the function find_in_set
select find_in_set('1','1,2,3,11,12')
You need the function FIND_IN_SET. Btw, '9%' should work, if the column contains the values you specified, are you sure you're querying
SELECT * FROM table WHERE field LIKE '9%'?
Standard SQL can do it as well:
...
WHERE
',' + SetValue + ',' LIKE '%,1,%'
AND ',' + SetValue + ',' NOT LIKE '%,11,%'
This expression cannot make use of an index, therefore performance will degrade quickly as the table size rises.
For better performance your table should be properly normalized, e.g.
SetId SetValue
1 1
1 2
1 3
1 4
1 5
instead of
SetId SetValue
1 '1,2,3,4,5'