How to select strings in UUID format + case sensitive wildcards - sql

How can I select only strings in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX where X is any number or any UPPERcase (not lowercase) character?
Example dataset:
ed54cb09-b402-4551-912d-b8e0fec69d9e --I do not want to select this one
00029B19-80CC-4FF8-BE11-BDB55FC7FC2A --I do want to select this one
Some are all-caps, some are not, and this is a varchar field. I want to select only these all-caps UUIDs, excluding the rest.
Currently I'm using the _ wildcard to look for the basic UUID format, but looks like UPPER doesn't apply to the _ wildcard. Ex.:
SELECT mycolumn
FROM mytable t
WHERE t.mycolumn like UPPER('________-____-____-____-____________') COLLATE SQL_Latin1_General_Cp1_CS_AS

As mentioned, you can first check its all uppercase by comparing upper of your value with itself using a case sensitive collation. And then use your wildcard pattern (or a more precise one as shown below) to confirm the format is correct.
select
-- Precise check on allowed characters
case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
and X.Test like '[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]' then 1 else 0 end
-- Loose check on allowed character, but definitely upper case
, case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
and X.Test like '________-____-____-____-____________' then 1 else 0 end
-- Not sure why HABO deleted their answer, but the following works also
, case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
and try_convert(uniqueidentifier,X.Test) is not null then 1 else 0 end
-- And combining Shmiel's and Charleface's suggestions gives
, case when X.Test like replicate('[A-F0-9]', 8) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 12) collate Latin1_General_100_BIN2 then 1 else 0 end
from (
values ('ed54cb09-b402-4551-912d-b8e0fec69d9e'), ('00029B19-80CC-4FF8-BE11-BDB55FC7FC2A')
) X (Test);
I have to echo Larnu's comment here, that it seems quite an odd requirement which might be better solved by a system change elsewhere.

Related

How does Varchar equality work in SQL expressions?

How does varchar equality work in SQL and why? '1' is different from '1 ' actually. See the spaces in the right hand side operand:
SELECT CASE
WHEN '1' = '1 ' THEN 'yes'
ELSE 'no'
END
-- results in yes
The output is 'yes', but why?
This behavior is in accordance with the specs. From a very old version of specs:
3) The comparison of two character strings is determined as follows:
a) If the length in characters of X is not equal to the length in
characters of Y, then the shorter string is effectively replaced, for
the purposes of comparison, with a copy of itself that has been
extended to the length of the longer string by concatenation on the
right of one or more pad characters, where the pad character is chosen
based on CS. [...] Otherwise, the pad character is a <space>.
In plain english, yes, 1 and 1 ​ are compared equal but not 1 and ​ 1.
SQL will ignore all the trailing spaces while comparing your varchar value on =,>,<,>=,<= operators.
if you compare ' 1' and '1' then it give false. But '1 ' and '1' give true.
; with cte as (
SELECT ' 1' as a, '1' as b )
select case when a= b then 'dd' else 'ff' end from cte
Result
--------
ff
; with cte as (
SELECT '1 ' as a, '1' as b )
select case when a= b then 'dd' else 'ff' end from cte
Result
------
dd
It is kind sql internally perform RTRIM by default.
You may find this link for more info LINK
You are comparing two strings. When a string has spaces, it is different.
You can remove all spaces with REPLACE('1 ', ' ', '').
the two string '1' and '1 ' are not equal cause the space ..
for avoid this you should use trim
SELECT CASE
WHEN trim( '1' ) = trim('1 ' ) THEN 'yes'
ELSE 'no'
END

Replacing empty string in SQL using SELECT

I'm trying to replace empty strings with a value and I can't seem to find the best way to do this.
The issue is that SOME values in the phone_number column are in a format without the numbers. For example ( ) -
I want to replace those empty values with 000-0000. I tried to use the CASE WHEN function but that doesn't seem to address the problem. The COALESCE IFNULL won't work because technically the values aren't NULL just incomplete. I'm thinking perhaps the CASE WHEN function would work if I could figure out how to format the empty values correctly.
Here is an example of the code
SELECT
phone_column,
CASE
WHEN phone_column = '() -'
THEN '000-000'
ELSE SUBSTRING(phone_colum, 6, 8)
END AS Phone
FROM
client_table
ORDER BY
linkid_
declare #test table(ph varchar(20))
insert into #test
select '( ) -'
UNION
select ''
UNION
select '(123)-456-7890'
select case
when replace(ph,'( ) -','')='' then '000-000'
else substring(ph,6,8)
end
from #test
if you want to search in a varchar then use LIKE this would help you in using expressions. For instance, in your case phone_column = '() -' would be phone_column LIKE '() -%' this will match any string that begins with () -. if you do phone_column = '() -' then it will only match the exact same string.
Any how, I'm not sure why you want to take this road, while you can validate the current numbers and try to only store the valid ones, as storing invalid numbers would be useless.
I'll give you an example,
to validate phone numbers, you first take out any existed formats (parentheses, dashes, spaces) then you'll be end up with a whole number with 10 or 7 digits. depends on your way of storing phone numbers. any numbers less than that would be invalid.
To remove the formats :
SELECT REPLACE(REPLACE(REPLACE(REPLACE(Number,'(',''),')',''),'-',''),' ','')
Now you will have only numbers, which will be easier to handle.
Like this :
SELECT
phone_column
FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(phone_column,'(',''),')',''),'-',''),' ','') phone_column FROM client_table) D
PS : Some countries phone numbers begins with 0, if your numbers don't
begin with 0, then you would cast the number to BIGINT, which will
remove any leading zeros.
Now, you can use the case to validate the numbers and do whatever you like with them.
SELECT
CASE
WHEN LEN(phone_column) = 10
THEN '(' + SUBSTRING(phone_column,1,3) + ') ' + SUBSTRING(phone_column, 3,3) + '-' + SUBSTRING(phone_column, 6,4)
ELSE '(000) 000-0000'
END Phone
FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(phone_column,'(',''),')',''),'-',''),' ','') phone_column FROM client_table) D

Validating string format using sql server

Check if the string is following the correct format or not. The correct format is as follows:
2 upper case letters; 2 digits; 1 to 30 characters alpha-numerical (case insensitive)
e.g. GB29RBOS60161331926819,
GB29RBOS60161331926819A,
GB29RBOS60161331926819B1
So far this is what i have got...
declare #accountNumber varchar(1000) = 'GB99AERF12FDG8AERF12FDG8AERF12FDG8'
select
case when #accountNumber not like '[A-Z][A-Z][0-9][0-9][0-9a-zA-Z]{30}$'
then 'ERROR' else null end
First, your structure assumes a case sensitive collation. Second, SQL Server doesn't recognize {} or $, so you have to repeat the pattern. However, you want up to 30 characters, so splitting the pieces apart is probably the best solution:
select (case when len(#accountNumber) not between 5 and 34 or
#accountNumber not like '[A-Z][A-Z][0-9][0-9]%' or
right(#accountNumber, 34) like '%[^A-Za-z0-9]%'
then 'ERROR'
end)
I think this should work... taking some tips from John.
declare #table table (i varchar(36))
insert into #table
values
('GR09xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), --30 x's
('GR09xxxxxxxxxxxxxxxxxxxxxxxxxxxx'), --28 x's
('GR09xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), --31 x's
('Gx09xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), --lower case 2'd letter
('G509xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), --digit second letter
('GRg9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') --charcater first number (3rd index)
select
case
when i + replicate('a',case when 34-len(i) < 0 then 0 else 34-len(i) end) not like '[A-Z][A-Z][0-9][0-9]' + replicate('[a-zA-Z0-9]',30)
then 'ERROR' else null end
from #table

SQL - string comparison ignores space

This query:
SELECT CASE WHEN 'abc ' = 'abc' THEN 1 ELSE 0 END
Returns 1, even though 'abc ' clearly is not equal to 'abc'. Similarly,
SELECT CASE WHEN 'abc ' LIKE '%c' THEN 1 ELSE 0 END
Also returns 1. However, a very similar query:
SELECT * FROM #tempTable WHERE Name LIKE '%c'
Did not return a row where Name = 'abc '.
SQL Server 2008 R2, Windows 7 & 2008 R2, x64.
= ignores trailing space
len ignores training space
like does not ignore trailing space
SELECT CASE WHEN 'abc ' = 'abc' and DATALENGTH('abc ') = DATALENGTH('abc')
THEN 1 ELSE 0 END
You can assert DATALENGTH is not relevant but it is still the solution.
Turns out that the Name column was NVARCHAR (even though it contained ASCII characters only) and NVARCHAR behaves differently than VARCHAR:
SELECT CASE WHEN N'abc ' LIKE 'abc' THEN 1 ELSE 0 END
Returns 0, ditto for column instead of literal. The following does return 1 still:
SELECT CASE WHEN N'abc ' = 'abc' THEN 1 ELSE 0 END
So = and LIKE work differently, another peculiar difference.
If you need to compare things in this way but are restricted because your columns are of data type VARCHAR, something like this will basically fill the trailing space with an 'X' which will accomplish a failed comparison:
DECLARE #1 VARCHAR(5), #2 VARCHAR(5)
SET #1 = 'ABC '
SET #2 = 'ABC'
IF REPLACE(#1,' ','X') = REPLACE(#2,' ','X')
PRINT 'Equal'
ELSE
PRINT 'Not Equal'
Not rocket science, but at least a work around if you encounter a similar situation that you need to deal with :)
TA, I am not sure how you got zero by simply mentioning as unicode(N). I run your query and it giving me 1 only.
You can compare the LEN('abc ') and DATALENGTH('abc ') and can use those as per you requirement or you can replace the trailing space with some character to solve your problem.
I had a similar issue with a nvarchar column and wanted to fix the data so I did the following to find the data
select 'x' + username + 'x' from aspnet_users
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'
The where clause compares the username as is with the trimmed version
'x1234 x' <> 'x1234x'
To fix the data I just did an update
update aspnet_Users
set username = rtrim(username)
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'

How can I generate ID with Prefix, Numeric Number and suffix?

I want to generate an ID in MSSQL Server 2008. Which will be Prefix + Numeric Number + suffix Like 'PV#000001#SV'. Which will be user defined (depends on configuration ) prefix, numeric length, suffix and starting number. Numeric number will be increased every time.
I tied to write this :
Blockquote
ALTER PROCEDURE [dbo].[spACC_SELECT_VOUCHER_NUMBER]
#COMPANY_ID uniqueidentifier,
#VOUCHER_TYPE INT
AS BEGIN
DECLARE #IS_AUTOMETIC BIT = (SELECT VOUCHER_CONFIG_NUMBERING_METHOD
FROM ACC_VOUCHER_CONFIG WHERE
ACC_VOUCHER_CONFIG.VOUCHER_CONFIG_VALUE=#VOUCHER_TYPE )
IF(#IS_AUTOMETIC=1)
BEGIN
SELECT CASE WHEN SUBSTRING(V.VOUCHER_CODE, 7, 23) IS NULL
THEN CASE WHEN VC.VOUCHER_CONFIG_PREFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_PREFIX END +
RIGHT ('0000000000000'+ CAST( VC.VOUCHER_CONFIG_BEGINING_NUMBER AS VARCHAR), VC.VOUCHER_CONFIG_NUMERIC_WIDTH) +
CASE WHEN VC.VOUCHER_CONFIG_SUFFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_SUFFIX END
ELSE CASE WHEN VC.VOUCHER_CONFIG_PREFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_PREFIX END +
RIGHT ('0000000000000'+ CAST((CAST( SUBSTRING(V.VOUCHER_CODE, 7, 23) AS INT)+1) AS VARCHAR), VC.VOUCHER_CONFIG_NUMERIC_WIDTH) +
CASE WHEN VC.VOUCHER_CONFIG_SUFFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_SUFFIX END
END AS VOUCHER_CODE FROM ACC_VOUCHER_CONFIG VC
LEFT OUTER JOIN ACC_VOUCHER V ON VC.VOUCHER_CONFIG_VALUE = V.VOUCHER_TYPE
WHERE VC.COMPANY_ID=#COMPANY_ID AND VC.VOUCHER_CONFIG_VALUE=#VOUCHER_TYPE
END
END
When I change the numeric length / suffix its not working.
Thanks
Nahid
For the six-digit number you're struggling with, add leading zeroes like this:
SELECT RIGHT('00000'+ CONVERT(VARCHAR,Num),6) AS NUM FROM your_table
Where Num is your sequential number.
This prepends 5 zeroes and then takes the right 6 characters from the resulting string.
A more detailed writeup of custom ID generation is here:
http://www.sqlteam.com/article/custom-auto-generated-sequences-with-sql-server
My suggestion would be to store just a number in the database (i.e. an int) and format the ID client side with tools that are better suited for it (i.e. a programming language that has sprintf or equivalent string formatting).