Generate short and Unique String values in SQL - sql

I am building an application, which needs a unique identifier as a UserID (example A3D7sRt).
In my case i have instructed not to use numbers only UserID and It should be auto-generated. And also the user id should be 6-8 character long. This is because it has to be easily memorized.
Here using GUID is not an option for me. Because GUID is HEX in nature, so i will be getting less number of unique values compared to a string in the same length.
So what is the efficient way to do that in SQL? Also i do not want to run into frequent unique constraint failed exception.
This value is then used to login to the android mobile client. And no passwords in the login process.

Based on Martin Smith and Zohar Peled comments, I have found a solution.
Take a bigint (probably your primary key)
Encode it as BASE36
bigint must not be 0. Take higher number (or start from) to get
output length greater than 6 characters
Here is the T-SQL
DECLARE #Result VARCHAR(MAX) = ''
DECLARE #Val BIGINT = 101722230
IF (#Val <= 1000000)
BEGIN
Select 'Very Small ID Try With Large BIGINT'
return;
END
WHILE (#Val > 0)
BEGIN
SELECT #Result = CHAR(#Val % 36 + CASE WHEN #Val % 36 < 10 THEN 48 ELSE 55 END) + #Result,
#Val = FLOOR(#Val/36)
END
SElect #Result
Output
1OK9DI is the output for the above code. (Verified)
Thank you everyone who helped me by commenting to this question.

Related

How can we read a varchar column, take the integer part out and add new column incrementing that integer part using script

I need to write a SCRIPT for below scenario:
We have a column X with rows value for this column X as X01,X02,X03,X04........
The problem I am stuck with is that I needed to add another row to this table based on the value of the last row that is X04, Well I am able to identify the logic that I need to work which is given below:
I need to read value X04
Take the integer part 04
Increment by 1 => 05
Save column value as X05
I am able to pass with the 1st step which is not very hard. The problem that I am facing is the next steps. I have researched and tried quite a lot commands but none worked.
Any help is highly appreciated. Thanks.
You seem to be describing:
select concat(left(max(x), 1),
right(concat('00', try_convert(int, right(max(x), 2)) + 1), 2)
from t;
This is doing the following:
Taking the left most character.
Converting the two right characters to a number and adding one.
Converting that back to a zero-padded string.
Here is a db<>fiddle.
Now: That you want to increment a string value seems broken. You should just use an identity column or sequence to assign a number. You can format the value as a string when you query the table -- or use a computed column to store that.
Try below Script
CREATE TABLE #table (x varchar(20))
INSERT INTO #table VALUES('X01'),('X02'),('X03'),('X04')
DECLARE #maxno NVARCHAR(20)
DECLARE #maxstring NVARCHAR(20)
DECLARE #finalno NVARCHAR(20)
DECLARE #loopminno INT =1 -- you can change based on the requirement
DECLARE #loopmaxno INT =10 -- how many number we want to increment
WHILE #loopminno < #loopmaxno
BEGIN
select #maxno = MAX(CAST(SUBSTRING(x, PATINDEX('%[0-9]%', x), 100) as INT))
, #maxstring = MAX(SUBSTRING(x, 1, PATINDEX('%[0-9]%',x)-1))
from #table
where PATINDEX('%[1-9]%',x)>0
SELECT #finalno = #maxstring + CASE WHEN CAST(#maxno AS INT)<9 THEN '0' ELSE '' END + CAST(#maxno+1 AS VARCHAR(20))
INSERT INTO #table
SELECT #finalno
SET #loopminno = #loopminno+1
END

Needing to parse out data

I am trying to parse out certain data from a string and I am having issues.
Here is the string:
1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found
I need to return this "REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR."
Here is my query SELECT CONVERT(VARCHAR(5000),CHARINDEX('14=',Column))FROM Table
If you're parsing, can we assume that you don't know what might come after the '^14=', but you need to capture whatever does? So searching for a particular string won't work because anything could come after '^14='. The best approach is to identify the longest reliable specific string that gives you a "foothold" to find the data you're looking for. What you don't want to do is accidentally capture the wrong data if the '^14=' appears more than once in your string. It looks like the '^' is your delimiter, since I don't see one at the start of the string. So you were actually on the right track, you just need to use SUBSTRING as a commenter mentioned. You also need to identify a marker for the end of the error message, which looks like it might be the next occurring '^', correct? Check several samples to be sure of this, and make sure the end marker doesn't at any point exist before your start marker or you'll get an error.
SELECT CAST((SUBSTRING(Column,CHARINDEX('14=',Column,0),CHARINDEX('^',Column,CHARINDEX('14=',Column,0) + 1) - CHARINDEX('14=',Column,0))) AS VARCHAR(5000)) FROM Table
You may need to increment or decrement the start position and end position by doing a +1 or -1 to fully capture your error message. But this should dynamically grab any length error message provided you are positive of your starting and ending markers.
I also have here a table-valued parsing function, where you would pass it the string and the '^' and it will return a table of data with not only the 14=, but everything.
CREATE function [dbo].[fn_SplitStringByDelimeter]
(
#list nvarchar(8000)
,#splitOn char(1)
)
returns #rtnTable table
(
id int identity(1,1)
,value nvarchar(100)
)
as
begin
declare #index int
declare #string nvarchar(4000)
select #index = 1
if len(#list) < 1 or #list is null return
--
while #index!= 0
begin
set #index = charindex(#splitOn,#list)
if #index!=0
set #string = left(#list,#index - 1)
else
set #string = #list
if(len(#string)>0)
insert into #rtnTable(value) values(#string)
--
set #list = right(#list,len(#list) - #index)
if len(#list) = 0 break
end
return
end
It sounds like you're trying to get the value of argument 14. This should do it:
select substring(
someData
, charindex('^14=',someData) + 4
, charindex('^',someData, charindex('^14=',someData) + 4) - charindex('^14=',someData) - 4
) errorMessage
from myData
where charindex('^14=',someData) > 0
and charindex('^',someData, charindex('^14=',someData) + 4) > 0
Try it here: http://sqlfiddle.com/#!18/22f23/2
This gets a substring of the given input.
The substring starts at the first character after the string ^14=; i.e. we get the index of ^14= in the string, then add 4 to it to skip over the matched characters themselves.
The substring ends at the first ^ character after the one in ^14=. We get the index of that character, then subtract the starting position from it to get the length of the desired output.
Caveats: If there is no parameter (^) after ^14= this will not work. Equally if there is no ^14= (even if the string starts 14=) this will not work. From the information available that's OK; but if this is a concern please say and we can provide something to handle that more complex scenario.
Code to create table & populate demo data
create table myData (someData nvarchar(256))
insert myData (someData)
values ('1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found')
, ('1xx^14=something else.^10=xx')
You could try to use a Case When statement with wildcards to find the value that you want.
Example:
SELECT
CASE
WHEN x LIKE '%REP Not Found%'
THEN 'REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR'
ELSE
''
END AS x
FROM
#T1
You could use this query (assuming MySQL database):
-- item is the column that contains the string
select SUBSTR(item, LOCATE('REP',item), LOCATE('REPRGR.',item) + LENGTH('REPRGR.') - LOCATE('REP', item)) info_msg from Table;
Illustration:
create table parsetest (item varchar(5000));
insert into parsetest values('1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found');
select * from parsetest;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| item |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
select SUBSTR(item, LOCATE('REP',item), LOCATE('REPRGR.',item) + LENGTH('REPRGR.') - LOCATE('REP', item)) info_msg from parsetest;
+------------------------------------------------------+
| info_msg |
+------------------------------------------------------+
| REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR. |
+------------------------------------------------------+

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).

Modify int result of count in sql server 2005

I am working on sql server 2005 and I am taking count from a specific table
SELECT count(StudentIdReference) as studentCount FROM StudentTable
Right now this select statement is returning me result like 2 or 78 or 790. But in future it will grow rapidly and on UI I don't have sufficient space to show the digit like 1000000.
What I want that after 3 digit, I will get the number like 1K or 1.6K, just as we see on stackoverflow.
This would be simpler to be done in the Presentation Layer of your application.
You coud write a user function and do something like this....
CREATE FUNCTION prettyPrint
(#number int)
RETURNS varchar(30)
AS
BEGIN
declare #return varchar(30)
set #return = cast(#number as varchar(3))
if #number > 1000
set #return = ''+ cast((#number/1000) as varchar(3)) + '.' + cast((#number % 1000)/100 as varchar(3)) +'K'
-- here must be more 'exceptions' or change all this about the magic number 1000
return #return
end
select dbo.prettyPrint(1500)
SELECT prettyPrint(count(StudentIdReference)) as studentCount FROM StudentTable
As others have stated you should really be doing this in your Presentation Layer not at the DB, however, this will do it for you:
Declare #StudentCount int,
#StudentCountFormatted varchar(10)
Select #StudentCount = Count(StudentIdReference) as studentCount FROM StudentTable
If #StudentCount > 999
Begin
Select #StudentCountFormatted = Convert(Varchar(10), Convert(numeric(19,1), (#StudentCount/ 1000.00))) + 'K'
End
Else
Begin
Select #StudentCountFormatted = #StudentCount
End
Select #StudentCountFormatted
You need to write your own logic to show such text. There is no built-in method.
I would return the COUNT as-is from SQL Server and leave the formatting up to the UI. This is because:
1) usually easier/performant to do formatting/string manipulation outside of SQL
2) different places in your code using the same query may want to use the data in different ways (maybe not now, but could do in future) so returning the count as-is gives you that flexibility - i.e. won't need 1 version to return the count as an INT and another to return the same as a formatted VARCHAR
You could do it in SQL, but in general I believe in pushing this in to the UI as it's a display/formatting behaviour.
You can always try something like this
SELECT
CASE
WHEN len(cast(count(*) as varchar(10)))< 4 then cast(count(*) as varchar(10))
WHEN len(cast(count(*) as varchar(10)))> 4 and len(cast(count(*)as varchar(10)))< 7
THEN cast(cast(count(*) / 1000.0 as decimal(10,1)) as varchar(10)) + 'k'
ELSE cast(cast(count(*) / 1000000.0 as decimal(10,1)) as varchar(10)) + 'm'
END StudentCount
FROM StudentTable

Creating a Function in SQL Server with a Phone Number as a parameter and returns a Random Number

I am hoping someone can help me here as google is not being as forthcoming as I would have liked. I am relatively new to SQL Server and so this is the first function I have set myself to do.
The outline of the function is that it has a Phone number varchar(15) as a parameter, it checks that this number is a proper number, i.e. it is 8 digits long and contains only numbers. The main character I am trying to avoid is '+'. Good Number = 12345678 Bad Number = +12345678. Once the number is checked I would like to produce a random number for each phone number that is passed in.
I have looked at substrings, the like operator, Rand(), left(), Right() in order to search through the number and then produce a random number. I understand that Rand() will produce the same random number unless alterations are done to it but right now it is about actually getting some working code. Any hints on this would be great or even point me towards some more documentation. I have read books online and they haven't helped me, maybe I am not looking in the right places.
Here is a snippet of code I was working on the Rand
declare #Phone Varchar (15)
declare #Counter Varchar (1)
declare #NewNumber Varchar(15)
set #Phone = '12345678'
set #Counter = len(#Phone)
while #Counter > 0
begin
select case when #Phone like '%[0-9]%' then cast(rand()*100000000 as int) else 'Bad Number' end
set #counter = #counter - 1
end
return
Thanks for the help in advance
Emer
Simply use LIKE and ensure each digit is between 0 and 9.
One way to generate random numbers is CHECKSUM(NEWID()), or use this as the seed for RAND
IF #phone LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
SELECT #NewNumber = LEFT(
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)) +
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)) +
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)), 15)
Or the double negative LIKE with length check
IF #phone NOT LIKE '%[^0-9]%' AND LEN(#phone) = 8
SELECT #NewNumber = LEFT(
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)) +
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)) +
CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)), 15)
I thought I would update my post with the solution I have come up with for other people who may be searching for something similar. From my research you are unable to use RAND() within a UDF. Instead you have to create a view and call it from that view.
Create Function [dbo].[AlterPhone](#Phone Varchar(15))
Returns varchar (15)
AS
BEGIN
declare #Counter int
declare #NewNumber varchar(15)
set #NewNumber = 0
select #NewNumber = case when len(#Phone)=8 and isnumeric(#Phone) = 1
then (select RandValue from dbo.vw_RandomVarchar) else 'Bad Number' end
return #NewNumber
END
/*
CREATE VIEW [dbo].[vw_RandomVarchar]
AS
SELECT cast(cast(rand()*100000000 as int)as varchar) AS RandValue
END
SELECT dbo.AlterPhone(12345678)
*/