Concatenate Two double precisions into a string in sql server 2008 function - sql

I have a Question regarding a Transact SQL Function.
What I need is to combine two INT values into a VARCHAR value. E.g. Lower Limit = '5', Upper Limit = '15'
My result should be "5 - 15"
Table looks like this:
ID Lower Limit Upper Limit
1 5 15
2 3 19
etc.
Code is like this so far.. All that there is left is to combine the two results:
Any help would be greatly appreciated !
CREATE FUNCTION [dbo].[GiveMeTheRange] (#argID INT)
RETURNS VARCHAR
AS
BEGIN
DECLARE #Range VARCHAR;
DECLARE #LowerLimit DOUBLE PRECISION;
DECLARE #UpperLimit DOUBLE PRECISION;
SELECT #LowerLimit = [Lower Limit]
FROM T_VormFactorKlassen
WHERE (ID = (#argID)
SELECT #UpperLimit = [Upper Limit]
FROM T_VormFactorKlassen
WHERE (ID = (#argID)
-- concattenate(#LowerLimit ' - ' #UpperLimit) <----That ain't workin'
RETURN #VormFactorKlasseNaam ;
END
Thanks

Try this:
SET #VormFactorKlasseNaam = CAST(#LowerLimit as varchar(5)) + ' - ' +
cast(#UpperLimit as varchar(5))

You really should avoid doing this kind of stuff with scalar functions. That said, this should work:
CREATE FUNCTION [dbo].[GiveMeTheRange] (#argID INT)
RETURNS VARCHAR(23) -- Always specify the length of the VARCHAR
AS
BEGIN
DECLARE #Range VARCHAR(23);
DECLARE #LowerLimit DOUBLE PRECISION;
DECLARE #UpperLimit DOUBLE PRECISION;
SELECT #LowerLimit = [Lower Limit]
FROM T_VormFactorKlassen
WHERE ID = (#argID)
SELECT #UpperLimit = [Upper Limit]
FROM T_VormFactorKlassen
WHERE ID = (#argID)
-- concattenate(#LowerLimit ' - ' #UpperLimit) <----That ain't workin'
SET #Range = CAST(#LowerLimit AS VARCHAR(10)) + ' - ' +
CAST(#UpperLimit AS VARCHAR(10))
RETURN #Range;
END

Related

ADD thousands separators to an Aggregate Sum SQL [duplicate]

I'm running some administrative queries and compiling results from sp_spaceused in SQL Server 2008 to look at data/index space ratios of some tables in my database. Of course I am getting all sorts of large numbers in the results and my eyes are starting to gloss over. It would be really convenient if I could format all those numbers with commas (987654321 becomes 987,654,321). Funny that in all the many years I've used SQL Server, this issue has never come up since most of the time I would be doing formatting at the presentation layer, but in this case the T-SQL result in SSMS is the presentation.
I've considered just creating a simple CLR UDF to solve this, but it seems like this should be do-able in just plain old T-SQL. So, I'll pose the question here - how do you do numeric formatting in vanilla T-SQL?
In SQL Server 2012 and higher, this will format a number with commas:
select format([Number], 'N0')
You can also change 0 to the number of decimal places you want.
While I agree with everyone, including the OP, who says that formatting should be done in the presentation layer, this formatting can be accomplished in T-SQL by casting to money and then converting to varchar. This does include trailing decimals, though, that could be looped off with SUBSTRING.
SELECT CONVERT(varchar, CAST(987654321 AS money), 1)
I'd recommend Replace in lieu of Substring to avoid string length issues:
REPLACE(CONVERT(varchar(20), (CAST(SUM(table.value) AS money)), 1), '.00', '')
For SQL Server 2012+ implementations, you will have the ability to use the FORMAT to apply string formatting to non-string data types.
In the original question, the user had requested the ability to use commas as thousands separators. In a closed as duplicate question, the user had asked how they could apply currency formatting. The following query shows how to perform both tasks. It also demonstrates the application of culture to make this a more generic solution (addressing Tsiridis Dimitris's function to apply Greek special formatting)
-- FORMAT
-- http://msdn.microsoft.com/en-us/library/hh213505(v=sql.110).aspx
-- FORMAT does not do conversion, that's the domain of cast/convert/parse etc
-- Only accepts numeric and date/time data types for formatting.
--
-- Formatting Types
-- http://msdn.microsoft.com/en-us/library/26etazsy.aspx
-- Standard numeric format strings
-- http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx
SELECT
-- c => currency
-- n => numeric
FORMAT(987654321, N'N', C.culture) AS some_number
, FORMAT(987654321, N'c', C.culture) AS some_currency
, C.culture
FROM
(
-- Language culture names
-- http://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx
VALUES
('en-US')
, ('en-GB')
, ('ja-JP')
, ('Ro-RO')
, ('el-GR')
) C (culture);
SQLFiddle for the above
Demo 1
Demonstrates adding commas:
PRINT FORMATMESSAGE('The number is: %s', format(5000000, '#,##0'))
-- Output
The number is: 5,000,000
Demo 2
Demonstrates commas and decimal points. Observe that it rounds the last digit if necessary.
PRINT FORMATMESSAGE('The number is: %s', format(5000000.759145678, '#,##0.00'))
-- Output
The number is: 5,000,000.76
Compatibility
SQL Server 2012+.
Please try with below query:
SELECT FORMAT(987654321,'#,###,##0')
Format with right decimal point :
SELECT FORMAT(987654321,'#,###,##0.###\,###')
SELECT REPLACE(CONVERT(varchar(20), (CAST(9876543 AS money)), 1), '.00', '')
output= 9,876,543
and you can replace 9876543 by your column name.
Tried the money trick above, and this works great for numerical values with two or less significant digits. I created my own function to format numbers with decimals:
CREATE FUNCTION [dbo].[fn_FormatWithCommas]
(
-- Add the parameters for the function here
#value varchar(50)
)
RETURNS varchar(50)
AS
BEGIN
-- Declare the return variable here
DECLARE #WholeNumber varchar(50) = NULL, #Decimal varchar(10) = '', #CharIndex int = charindex('.', #value)
IF (#CharIndex > 0)
SELECT #WholeNumber = SUBSTRING(#value, 1, #CharIndex-1), #Decimal = SUBSTRING(#value, #CharIndex, LEN(#value))
ELSE
SET #WholeNumber = #value
IF(LEN(#WholeNumber) > 3)
SET #WholeNumber = dbo.fn_FormatWithCommas(SUBSTRING(#WholeNumber, 1, LEN(#WholeNumber)-3)) + ',' + RIGHT(#WholeNumber, 3)
-- Return the result of the function
RETURN #WholeNumber + #Decimal
END
This belongs in a comment to Phil Hunt's answer but alas I don't have the rep.
To strip the ".00" off the end of your number string, parsename is super-handy.
It tokenizes period-delimited strings and returns the specified element, starting with the rightmost token as element 1.
SELECT PARSENAME(CONVERT(varchar, CAST(987654321 AS money), 1), 2)
Yields "987,654,321"
here is another t-sql UDF
CREATE FUNCTION dbo.Format(#num int)
returns varChar(30)
As
Begin
Declare #out varChar(30) = ''
while #num > 0 Begin
Set #out = str(#num % 1000, 3, 0) + Coalesce(','+#out, '')
Set #num = #num / 1000
End
Return #out
End
`/* Author: Tsiridis Dimitris */
/* Greek amount format. For the other change the change on replace of '.' & ',' */
CREATE FUNCTION dbo.formatAmount (
#amtIn as varchar(20)
) RETURNS varchar(20)
AS
BEGIN
return cast(REPLACE(SUBSTRING(CONVERT(varchar(20), CAST(#amtIn AS money), 1),1,
LEN(CONVERT(varchar(20), CAST(#amtIn AS money), 1))-3), ',','.')
+ replace(RIGHT(CONVERT(varchar(20), CAST(#amtIn AS money), 1),3), '.',',') AS VARCHAR(20))
END
SELECT [geniki].[dbo].[formatAmount]('9888777666555.44')`
Here is a scalar function I am using that fixes some bugs in a previous example (above) and also handles decimal values (to the specified # of digits) (EDITED to also work with 0 & negative numbers). One other note, the cast as money method above is limited to the size of the MONEY data type, and doesn't work with 4 (or more) digits decimals. That method is definitely simpler but less flexible.
CREATE FUNCTION [dbo].[fnNumericWithCommas](#num decimal(38, 18), #decimals int = 4) RETURNS varchar(44) AS
BEGIN
DECLARE #ret varchar(44)
DECLARE #negative bit; SET #negative = CASE WHEN #num < 0 THEN 1 ELSE 0 END
SET #num = abs(round(#num, #decimals)) -- round the value to the number of decimals desired
DECLARE #decValue varchar(18); SET #decValue = substring(ltrim(#num - round(#num, 0, 1)) + '000000000000000000', 3, #decimals)
SET #num = round(#num, 0, 1) -- truncate the incoming number of any decimals
WHILE #num > 0 BEGIN
SET #ret = str(#num % 1000, 3, 0) + isnull(','+#ret, '')
SET #num = round(#num / 1000, 0, 1)
END
SET #ret = isnull(replace(ltrim(#ret), ' ', '0'), '0') + '.' + #decValue
IF (#negative = 1) SET #ret = '-' + #ret
RETURN #ret
END
GO
Another UDF which is hopefully generic enough and does not make assumptions about whether you want to round to a specific number of decimal places:
CREATE FUNCTION [dbo].[fn_FormatNumber] (#number decimal(38,18))
RETURNS varchar(50)
BEGIN
-- remove minus sign before applying thousands seperator
DECLARE #negative bit
SET #negative = CASE WHEN #number < 0 THEN 1 ELSE 0 END
SET #number = ABS(#number)
-- add thousands seperator for every 3 digits to the left of the decimal place
DECLARE #pos int, #result varchar(50) = CAST(#number AS varchar(50))
SELECT #pos = CHARINDEX('.', #result)
WHILE #pos > 4
BEGIN
SET #result = STUFF(#result, #pos-3, 0, ',')
SELECT #pos = CHARINDEX(',', #result)
END
-- remove trailing zeros
WHILE RIGHT(#result, 1) = '0'
SET #result = LEFT(#result, LEN(#result)-1)
-- remove decimal place if not required
IF RIGHT(#result, 1) = '.'
SET #result = LEFT(#result, LEN(#result)-1)
IF #negative = 1
SET #result = '-' + #result
RETURN #result
END
/*
#------------------------------------------------------------------------#
# SQL Query Script #
# ---------------- #
# Funcion.: dbo.fn_nDerecha ( Numero, Pos_Enteros, Pos_Decimales ) #
# Numero : es el Numero o Valor a formatear #
# Pos_Enteros : es la cantidad posiciones para Enteros #
# Pos_Decimales : es la cantidad posiciones para Decimales #
# #
# OBJETIVO: Formatear los Numeros con Coma y Justificado a la Derecha #
# Por Ejemplo: #
# dbo.fn_nDerecha ( Numero, 9, 2 ) Resultado = ---,---,--9.99 #
# dado Numero = 1234.56 Resultado = 1,234.56 #
# dado Numero = -1.56 Resultado = -1.56 #
# dado Numero = -53783423.56 Resultado = -53,783,423.56 #
# #
# Autor...: Francisco Eugenio Cabrera Perez #
# Fecha...: Noviembre 25, 2015 #
# Pais....: Republica Dominicana #
#------------------------------------------------------------------------#
*/
CREATE FUNCTION [dbo].[fn_nDerecha]
(
-- Agregue Argumentos, para personalizar la funcion a su conveniencia
#Numero_str varchar(max)
,#Pos_Enteros int
,#Pos_Decimales int
)
RETURNS varchar(max)
AS
BEGIN
-- Declare la variable del RETURN aqui, en este caso es RESULT
declare #RESULTADO varchar(max)
set #RESULTADO = '****'
----------------------------------------------- --
declare #Numero_num numeric(28,12)
set #Numero_num =
(
case when isnumeric(#Numero_str) = 0
then 0
else round (convert( numeric(28,12), #Numero_str), #Pos_Decimales)
end
)
-- ----------------------------------------------- --
-- Aumenta #Pos_Enteros de #RESULTADO,
-- si las posiciones de Enteros del dato #Numero_str es Mayor...
--
declare #Num_Pos_Ent int
set #Num_Pos_Ent = len ( convert( varchar, convert(int, abs(#Numero_num) ) ) )
--
declare #Pos_Ent_Mas int
set #Pos_Ent_Mas =
(
case when #Num_Pos_Ent > #Pos_Enteros
then #Num_Pos_Ent - #Pos_Enteros
else 0
end
)
set #Pos_Enteros = #Pos_Enteros + #Pos_Ent_Mas
--
-- ----------------------------------------------- --
declare #p_Signo_ctd int
set #p_Signo_ctd = (case when #Numero_num < 1 then 1 else 0 end)
--
declare #p_Comas_ctd int
set #p_Comas_ctd = ( #Pos_Enteros - 1 ) / 3
--
declare #p_Punto_ctd int
set #p_Punto_ctd = (case when #Pos_Decimales > 0 then 1 else 0 end)
--
declare #p_input_Longitud int
set #p_input_Longitud = ( #p_Signo_ctd + #Pos_Enteros ) +
#p_Punto_ctd + #Pos_Decimales
--
declare #p_output_Longitud int
set #p_output_Longitud = ( #p_Signo_ctd + #Pos_Enteros + #p_Comas_ctd )
+ ( #p_Punto_ctd + #Pos_Decimales )
--
-- =================================================================== --
declare #Valor_str varchar(max)
set #Valor_str = str(#Numero_num, #p_input_Longitud, #Pos_Decimales)
declare #V_Ent_str varchar(max)
set #V_Ent_str =
(case when #Pos_Decimales > 0
then substring( #Valor_str, 0, charindex('.', #Valor_str, 0) )
else #Valor_str end)
--
declare #V_Dec_str varchar(max)
set #V_Dec_str =
(case when #Pos_Decimales > 0
then '.' + right(#Valor_str, #Pos_Decimales)
else '' end)
--
set #V_Ent_str = convert(VARCHAR, convert(money, #V_Ent_str), 1)
set #V_Ent_str = substring( #V_Ent_str, 0, charindex('.', #V_Ent_str, 0) )
--
set #RESULTADO = #V_Ent_str + #V_Dec_str
--
set #RESULTADO = ( replicate( ' ', #p_output_Longitud - len(#RESULTADO) ) + #RESULTADO )
--
-- =================================================================== -
-- =================================================================== -
RETURN #RESULTADO
END
-- =================================================================== --
/*
This function needs 3 arguments: the First argument is the #Numero_str which the Number as data input, and the other 2 arguments specify how the information will be formatted for the output, those arguments are #Pos_Enteros and #Pos_Decimales which specify how many Integers and Decimal places you want to show for the Number you pass as input argument.
*/
For SQL Server before 2012 which does not include the FORMAT function, create this function:
CREATE FUNCTION FormatCurrency(#value numeric(30,2))
RETURNS varchar(50)
AS
BEGIN
DECLARE #NumAsChar VARCHAR(50)
SET #NumAsChar = '$' + CONVERT(varchar(50), CAST(#Value AS money),1)
RETURN #NumAsChar
END
select dbo.FormatCurrency(12345678)
returns $12,345,678.00
Drop the $ if you just want commas.

SQL change a string using a pattern

I need to do something special in SQL, I don't know if a standard function exists, I actually don't know what to search... ! So any advice would be appreciated.
Here is my problem:
I have a data which is a number: 7000000
And I have a "formatting pattern": ****5**
My goal is to merge both: result for this example is: 7000500
(a star means to keep the original value, and a number means to change it)
another example:
7894321
*0**9*1
-------
7094921
(I use SQL Server)
This task can be performed in any programming language with basic for-loop and and some internal functions to find substring and replace
Here is how it's done in SQL SERVER (given that the string and the format is of same length)
Create your own function
CREATE FUNCTION dbo.Formatter
(
#str NVARCHAR(MAX),
#format NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #i int = 1, #len int = LEN(#str)
-- Iterates over over each char in the FORMAT and replace the original string if applies
WHILE #i <= #len
BEGIN
IF SUBSTRING(#format, #i, 1) <> '*'
SET #str = STUFF(#str, #i, 1, SUBSTRING(#format, #i, 1))
SET #i = #i + 1
END
RETURN #str
END
USE your function in your SELECTs, e.g.
DECLARE #str VARCHAR(MAX) = '7894321'
DECLARE #format VARCHAR(MAX) = '*0**9*1'
PRINT('Format: ' + #format)
PRINT('Old string: ' + #str)
PRINT('New string: ' + dbo.Formatter(#str, #format))
Result:
Format: *0**9*1
Old string: 7894321
New string: 7094921
I would split the string into it's individual characters, use a CASE expression to determine what character should be retained, and then remerge. I'm going to assume you're on a recent version of SQL Server, and thus have access to STRING_AGG; if not, you'll want to use the "old" FOR XML PATH method. I also assume a string of length 10 of less (if it's more, then just increase the size of the tally).
DECLARE #Format varchar(10) = '****5**';
WITH Tally AS(
SELECT V.I
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))V(I))
SELECT STRING_AGG(CASE SSf.C WHEN '*' THEN SSc.C ELSE SSf.C END,'') WITHIN GROUP (ORDER BY T.I) AS NewString
FROM (VALUES(1,'7894321'),(2,'7000000'))YT(SomeID,YourColumn) --This would be your table
JOIN Tally T ON LEN(YT.YourColumn) >= T.I
CROSS APPLY (VALUES(SUBSTRING(YT.YourColumn,T.I,1)))SSc(C)
CROSS APPLY (VALUES(SUBSTRING(#Format,T.I,1)))SSf(C)
GROUP BY YT.SomeID;
db<>fiddle
If your value is an int and your format is an int also, then you can do this:
DECLARE #formatNum int = CAST(REPLACE(#format, '*', '0') AS int);
SELECT f.Formatted
FROM Table
CROSS APPLY (
SELECT Formatted = SUM(CASE
WHEN ((#FormatNum / Base) % 10) > 0
THEN ((#FormatNum / Base) % 10) * Base
ELSE ((t.MyNumber / Base) % 10) * Base END
FROM (VALUES
(10),(100),(1000),(10000),(100000),(1000000),(10000000),(100000000),(1000000000)
) v(Base)
) f
The / is integer division, % is modulo, so dividing a number by Base and taking the modulo 10 will give you exactly one digit.

how to truncate a number in sybase ASE?

http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1540/doc/html/san1278453173757.html
The functions TRUNCATE and TRUNCNUM are not supported in Adaptive Server Enterprise.
Does anyone know another way of doing this in ASE?
Thanks
I know these ways:
select Number = floor ( 455.443 )
select Number = cast ( 455.443 as int )
select Number = convert ( int, 455.443 )
select Number = 455.443 - ( 455.443 % 1 )
How about using the Floor function? It essentially does the same thing, and is supported in ASE.
This is an old question, but I did this a few days ago to mimic the "truncnum" function described in the link above.
create function custom_truncnum(#numberToTruncate float, #decimalPlaces int)
returns float
AS
declare #tenToTheXPower float;
declare #leftSideOfDecimal float;
declare #returnVal float;
set #tenToTheXPower = power(10, ABS(#decimalPlaces);
set #leftSideOfDecimal = FLOOR(#numberToTruncate);
if (#decimalPlaces <= 0)
set #returnVal = FLOOR(#numberToTruncate / #tenToTheXPower) * #tenToTheXPower;
else
set #returnVal = #leftSideOfDecimal + (FLOOR(#numberToTruncate - #leftSideOfDecimal) * #tenToTheXPower) / #tenToTheXPower);
return #returnVal;
GO
Now you should be able to do this in Sybase ASE:
SELECT dbo.custom_truncnum(345.567, 2)
345.56
SELECT dbo.custom_truncnum(345.562, 2)
345.56
SELECT dbo.custom_truncnum(345.567, -1)
340
SELECT dbo.custom_truncnum(345.567, -2)
300
SELECT dbo.custom_truncnum(345.567, 0) --This is the same as FLOOR(345.567)
345

Generating random strings with T-SQL

If you wanted to generate a pseudorandom alphanumeric string using T-SQL, how would you do it? How would you exclude characters like dollar signs, dashes, and slashes from it?
Using a guid
SELECT #randomString = CONVERT(varchar(255), NEWID())
very short ...
Similar to the first example, but with more flexibility:
-- min_length = 8, max_length = 12
SET #Length = RAND() * 5 + 8
-- SET #Length = RAND() * (max_length - min_length + 1) + min_length
-- define allowable character explicitly - easy to read this way an easy to
-- omit easily confused chars like l (ell) and 1 (one) or 0 (zero) and O (oh)
SET #CharPool =
'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789.,-_!$##%^&*'
SET #PoolLength = Len(#CharPool)
SET #LoopCount = 0
SET #RandomString = ''
WHILE (#LoopCount < #Length) BEGIN
SELECT #RandomString = #RandomString +
SUBSTRING(#Charpool, CONVERT(int, RAND() * #PoolLength) + 1, 1)
SELECT #LoopCount = #LoopCount + 1
END
I forgot to mention one of the other features that makes this more flexible. By repeating blocks of characters in #CharPool, you can increase the weighting on certain characters so that they are more likely to be chosen.
When generating random data, specially for test, it is very useful to make the data random, but reproducible. The secret is to use explicit seeds for the random function, so that when the test is run again with the same seed, it produces again exactly the same strings. Here is a simplified example of a function that generates object names in a reproducible manner:
alter procedure usp_generateIdentifier
#minLen int = 1
, #maxLen int = 256
, #seed int output
, #string varchar(8000) output
as
begin
set nocount on;
declare #length int;
declare #alpha varchar(8000)
, #digit varchar(8000)
, #specials varchar(8000)
, #first varchar(8000)
declare #step bigint = rand(#seed) * 2147483647;
select #alpha = 'qwertyuiopasdfghjklzxcvbnm'
, #digit = '1234567890'
, #specials = '_## '
select #first = #alpha + '_#';
set #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #length = #minLen + rand(#seed) * (#maxLen-#minLen)
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
declare #dice int;
select #dice = rand(#seed) * len(#first),
#seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = substring(#first, #dice, 1);
while 0 < #length
begin
select #dice = rand(#seed) * 100
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
if (#dice < 10) -- 10% special chars
begin
select #dice = rand(#seed) * len(#specials)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#specials, #dice, 1);
end
else if (#dice < 10+10) -- 10% digits
begin
select #dice = rand(#seed) * len(#digit)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#digit, #dice, 1);
end
else -- rest 80% alpha
begin
declare #preseed int = #seed;
select #dice = rand(#seed) * len(#alpha)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#alpha, #dice, 1);
end
select #length = #length - 1;
end
end
go
When running the tests the caller generates a random seed it associates with the test run (saves it in the results table), then passed along the seed, similar to this:
declare #seed int;
declare #string varchar(256);
select #seed = 1234; -- saved start seed
exec usp_generateIdentifier
#seed = #seed output
, #string = #string output;
print #string;
exec usp_generateIdentifier
#seed = #seed output
, #string = #string output;
print #string;
exec usp_generateIdentifier
#seed = #seed output
, #string = #string output;
print #string;
Update 2016-02-17: See the comments bellow, the original procedure had an issue in the way it advanced the random seed. I updated the code, and also fixed the mentioned off-by-one issue.
Use the following code to return a short string:
SELECT SUBSTRING(CONVERT(varchar(40), NEWID()),0,9)
If you are running SQL Server 2008 or greater, you could use the new cryptographic function crypt_gen_random() and then use base64 encoding to make it a string. This will work for up to 8000 characters.
declare #BinaryData varbinary(max)
, #CharacterData varchar(max)
, #Length int = 2048
set #BinaryData=crypt_gen_random (#Length)
set #CharacterData=cast('' as xml).value('xs:base64Binary(sql:variable("#BinaryData"))', 'varchar(max)')
print #CharacterData
I'm not expert in T-SQL, but the simpliest way I've already used it's like that:
select char((rand()*25 + 65))+char((rand()*25 + 65))
This generates two char (A-Z, in ascii 65-90).
select left(NEWID(),5)
This will return the 5 left most characters of the guid string
Example run
------------
11C89
9DB02
For one random letter, you can use:
select substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
(abs(checksum(newid())) % 26)+1, 1)
An important difference between using newid() versus rand() is that if you return multiple rows, newid() is calculated separately for each row, while rand() is calculated once for the whole query.
Here is a random alpha numeric generator
print left(replace(newid(),'-',''),#length) //--#length is the length of random Num.
There are a lot of good answers but so far none of them allow a customizable character pool and work as a default value for a column. I wanted to be able to do something like this:
alter table MY_TABLE add MY_COLUMN char(20) not null
default dbo.GenerateToken(crypt_gen_random(20))
So I came up with this. Beware of the hard-coded number 32 if you modify it.
-- Converts a varbinary of length N into a varchar of length N.
-- Recommend passing in the result of CRYPT_GEN_RANDOM(N).
create function GenerateToken(#randomBytes varbinary(max))
returns varchar(max) as begin
-- Limit to 32 chars to get an even distribution (because 32 divides 256) with easy math.
declare #allowedChars char(32);
set #allowedChars = 'abcdefghijklmnopqrstuvwxyz012345';
declare #oneByte tinyint;
declare #oneChar char(1);
declare #index int;
declare #token varchar(max);
set #index = 0;
set #token = '';
while #index < datalength(#randomBytes)
begin
-- Get next byte, use it to index into #allowedChars, and append to #token.
-- Note: substring is 1-based.
set #index = #index + 1;
select #oneByte = convert(tinyint, substring(#randomBytes, #index, 1));
select #oneChar = substring(#allowedChars, 1 + (#oneByte % 32), 1); -- 32 is the number of #allowedChars
select #token = #token + #oneChar;
end
return #token;
end
This worked for me: I needed to generate just three random alphanumeric characters for an ID, but it could work for any length up to 15 or so.
declare #DesiredLength as int = 3;
select substring(replace(newID(),'-',''),cast(RAND()*(31-#DesiredLength) as int),#DesiredLength);
Another simple solution with the complete alphabet:
SELECT LEFT(REPLACE(REPLACE((SELECT CRYPT_GEN_RANDOM(16) FOR XML PATH(''), BINARY BASE64),'+',''),'/',''),16);
Replace the two 16's with the desired length.
Sample result:
pzyMATe3jJwN1XkB
I realize that this is an old question with many fine answers. However when I found this I also found a more recent article on TechNet by Saeid Hasani
T-SQL: How to Generate Random Passwords
While the solution focuses on passwords it applies to the general case. Saeid works through various considerations to arrive at a solution. It is very instructive.
A script containing all the code blocks form the article is separately available via the TechNet Gallery, but I would definitely start at the article.
For SQL Server 2016 and later, here is a really simple and relatively efficient expression to generate cryptographically random strings of a given byte length:
--Generates 36 bytes (48 characters) of base64 encoded random data
select r from OpenJson((select Crypt_Gen_Random(36) r for json path))
with (r varchar(max))
Note that the byte length is not the same as the encoded size; use the following from this article to convert:
Bytes = 3 * (LengthInCharacters / 4) - Padding
I came across this blog post first, then came up with the following stored procedure for this that I'm using on a current project (sorry for the weird formatting):
CREATE PROCEDURE [dbo].[SpGenerateRandomString]
#sLength tinyint = 10,
#randomString varchar(50) OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE #counter tinyint
DECLARE #nextChar char(1)
SET #counter = 1
SET #randomString = ”
WHILE #counter <= #sLength
BEGIN
SELECT #nextChar = CHAR(48 + CONVERT(INT, (122-48+1)*RAND()))
IF ASCII(#nextChar) not in (58,59,60,61,62,63,64,91,92,93,94,95,96)
BEGIN
SELECT #randomString = #randomString + #nextChar
SET #counter = #counter + 1
END
END
END
I did this in SQL 2000 by creating a table that had characters I wanted to use, creating a view that selects characters from that table ordering by newid(), and then selecting the top 1 character from that view.
CREATE VIEW dbo.vwCodeCharRandom
AS
SELECT TOP 100 PERCENT
CodeChar
FROM dbo.tblCharacter
ORDER BY
NEWID()
...
SELECT TOP 1 CodeChar FROM dbo.vwCodeCharRandom
Then you can simply pull characters from the view and concatenate them as needed.
EDIT: Inspired by Stephan's response...
select top 1 RandomChar from tblRandomCharacters order by newid()
No need for a view (in fact I'm not sure why I did that - the code's from several years back). You can still specify the characters you want to use in the table.
I use this procedure that I developed simply stipluate the charaters you want to be able to display in the input variables, you can define the length too.
Hope this formats well, I am new to stack overflow.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND object_id = OBJECT_ID(N'GenerateARandomString'))
DROP PROCEDURE GenerateARandomString
GO
CREATE PROCEDURE GenerateARandomString
(
#DESIREDLENGTH INTEGER = 100,
#NUMBERS VARCHAR(50)
= '0123456789',
#ALPHABET VARCHAR(100)
='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
#SPECIALS VARCHAR(50)
= '_=+-$£%^&*()"!#~#:',
#RANDOMSTRING VARCHAR(8000) OUT
)
AS
BEGIN
-- Author David Riley
-- Version 1.0
-- You could alter to one big string .e.e numebrs , alpha special etc
-- added for more felxibility in case I want to extend i.e put logic in for 3 numbers, 2 pecials 3 numbers etc
-- for now just randomly pick one of them
DECLARE #SWAP VARCHAR(8000); -- Will be used as a tempoary buffer
DECLARE #SELECTOR INTEGER = 0;
DECLARE #CURRENTLENGHT INTEGER = 0;
WHILE #CURRENTLENGHT < #DESIREDLENGTH
BEGIN
-- Do we want a number, special character or Alphabet Randonly decide?
SET #SELECTOR = CAST(ABS(CHECKSUM(NEWID())) % 3 AS INTEGER); -- Always three 1 number , 2 alphaBET , 3 special;
IF #SELECTOR = 0
BEGIN
SET #SELECTOR = 3
END;
-- SET SWAP VARIABLE AS DESIRED
SELECT #SWAP = CASE WHEN #SELECTOR = 1 THEN #NUMBERS WHEN #SELECTOR = 2 THEN #ALPHABET ELSE #SPECIALS END;
-- MAKE THE SELECTION
SET #SELECTOR = CAST(ABS(CHECKSUM(NEWID())) % LEN(#SWAP) AS INTEGER);
IF #SELECTOR = 0
BEGIN
SET #SELECTOR = LEN(#SWAP)
END;
SET #RANDOMSTRING = ISNULL(#RANDOMSTRING,'') + SUBSTRING(#SWAP,#SELECTOR,1);
SET #CURRENTLENGHT = LEN(#RANDOMSTRING);
END;
END;
GO
DECLARE #RANDOMSTRING VARCHAR(8000)
EXEC GenerateARandomString #RANDOMSTRING = #RANDOMSTRING OUT
SELECT #RANDOMSTRING
Sometimes we need a lot of random things: love, kindness, vacation, etc.
I have collected a few random generators over the years, and these are from Pinal Dave and a stackoverflow answer I found once. Refs below.
--Adapted from Pinal Dave; http://blog.sqlauthority.com/2007/04/29/sql-server-random-number-generator-script-sql-query/
SELECT
ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1 AS RandomInt
, CAST( (ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1)/7.0123 AS NUMERIC( 15,4)) AS RandomNumeric
, DATEADD( DAY, -1*(ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1), GETDATE()) AS RandomDate
--This line from http://stackoverflow.com/questions/15038311/sql-password-generator-8-characters-upper-and-lower-and-include-a-number
, CAST((ABS(CHECKSUM(NEWID()))%10) AS VARCHAR(1)) + CHAR(ASCII('a')+(ABS(CHECKSUM(NEWID()))%25)) + CHAR(ASCII('A')+(ABS(CHECKSUM(NEWID()))%25)) + LEFT(NEWID(),5) AS RandomChar
, ABS(CHECKSUM(NEWID()))%50000+1 AS RandomID
This will produce a string 96 characters in length, from the Base64 range (uppers, lowers, numbers, + and /). Adding 3 "NEWID()" will increase the length by 32, with no Base64 padding (=).
SELECT
CAST(
CONVERT(NVARCHAR(MAX),
CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
,2)
AS XML).value('xs:base64Binary(xs:hexBinary(.))', 'VARCHAR(MAX)') AS StringValue
If you are applying this to a set, make sure to introduce something from that set so that the NEWID() is recomputed, otherwise you'll get the same value each time:
SELECT
U.UserName
, LEFT(PseudoRandom.StringValue, LEN(U.Pwd)) AS FauxPwd
FROM Users U
CROSS APPLY (
SELECT
CAST(
CONVERT(NVARCHAR(MAX),
CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), U.UserID) -- Causes a recomute of all NEWID() calls
,2)
AS XML).value('xs:base64Binary(xs:hexBinary(.))', 'VARCHAR(MAX)') AS StringValue
) PseudoRandom
CREATE OR ALTER PROC USP_GENERATE_RANDOM_CHARACTER ( #NO_OF_CHARS INT, #RANDOM_CHAR VARCHAR(40) OUTPUT)
AS
BEGIN
SELECT #RANDOM_CHAR = SUBSTRING (REPLACE(CONVERT(VARCHAR(40), NEWID()), '-',''), 1, #NO_OF_CHARS)
END
/*
USAGE:
DECLARE #OUT VARCHAR(40)
EXEC USP_GENERATE_RANDOM_CHARACTER 13,#RANDOM_CHAR = #OUT OUTPUT
SELECT #OUT
*/
Small modification of Remus Rusanu code -thanks for sharing
This generate a random string and can be used without the seed value
declare #minLen int = 1, #maxLen int = 612, #string varchar(8000);
declare #length int;
declare #seed INT
declare #alpha varchar(8000)
, #digit varchar(8000)
, #specials varchar(8000)
, #first varchar(8000)
declare #step bigint = rand() * 2147483647;
select #alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
, #digit = '1234567890'
, #specials = '_##-/\ '
select #first = #alpha + '_#';
set #seed = (rand(#step)*2147483647);
select #length = #minLen + rand(#seed) * (#maxLen-#minLen)
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
declare #dice int;
select #dice = rand(#seed) * len(#first),
#seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = substring(#first, #dice, 1);
while 0 < #length
begin
select #dice = rand(#seed) * 100
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
if (#dice < 10) -- 10% special chars
begin
select #dice = rand(#seed) * len(#specials)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#specials, #dice, 1);
end
else if (#dice < 10+10) -- 10% digits
begin
select #dice = rand(#seed) * len(#digit)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#digit, #dice, 1);
end
else -- rest 80% alpha
begin
declare #preseed int = #seed;
select #dice = rand(#seed) * len(#alpha)+1
, #seed = (rand((#seed+#step)%2147483647)*2147483647);
select #string = #string + substring(#alpha, #dice, 1);
end
select #length = #length - 1
end
SELECT #string
Heres something based on New Id.
with list as
(
select 1 as id,newid() as val
union all
select id + 1,NEWID()
from list
where id + 1 < 10
)
select ID,val from list
option (maxrecursion 0)
I thought I'd share, or give back to the community ...
It's ASCII based, and the solution is not perfect but it works quite well.
Enjoy,
Goran B.
/*
-- predictable masking of ascii chars within a given decimal range
-- purpose:
-- i needed an alternative to hashing alg. or uniqueidentifier functions
-- because i wanted to be able to revert to original char set if possible ("if", the operative word)
-- notes: wrap below in a scalar function if desired (i.e. recommended)
-- by goran biljetina (2014-02-25)
*/
declare
#length int
,#position int
,#maskedString varchar(500)
,#inpString varchar(500)
,#offsetAsciiUp1 smallint
,#offsetAsciiDown1 smallint
,#ipOffset smallint
,#asciiHiBound smallint
,#asciiLoBound smallint
set #ipOffset=null
set #offsetAsciiUp1=1
set #offsetAsciiDown1=-1
set #asciiHiBound=126 --> up to and NOT including
set #asciiLoBound=31 --> up from and NOT including
SET #inpString = '{"config":"some string value", "boolAttr": true}'
SET #length = LEN(#inpString)
SET #position = 1
SET #maskedString = ''
--> MASK:
---------
WHILE (#position < #length+1) BEGIN
SELECT #maskedString = #maskedString +
ISNULL(
CASE
WHEN ASCII(SUBSTRING(#inpString,#position,1))>#asciiLoBound AND ASCII(SUBSTRING(#inpString,#position,1))<#asciiHiBound
THEN
CHAR(ASCII(SUBSTRING(#inpString,#position,1))+
(case when #ipOffset is null then
case when ASCII(SUBSTRING(#inpString,#position,1))%2=0 then #offsetAsciiUp1 else #offsetAsciiDown1 end
else #ipOffset end))
WHEN ASCII(SUBSTRING(#inpString,#position,1))<=#asciiLoBound
THEN '('+CONVERT(varchar,ASCII(SUBSTRING(#Inpstring,#position,1))+1000)+')' --> wrap for decode
WHEN ASCII(SUBSTRING(#inpString,#position,1))>=#asciiHiBound
THEN '('+CONVERT(varchar,ASCII(SUBSTRING(#inpString,#position,1))+1000)+')' --> wrap for decode
END
,'')
SELECT #position = #position + 1
END
select #MaskedString
SET #inpString = #maskedString
SET #length = LEN(#inpString)
SET #position = 1
SET #maskedString = ''
--> UNMASK (Limited to within ascii lo-hi bound):
-------------------------------------------------
WHILE (#position < #length+1) BEGIN
SELECT #maskedString = #maskedString +
ISNULL(
CASE
WHEN ASCII(SUBSTRING(#inpString,#position,1))>#asciiLoBound AND ASCII(SUBSTRING(#inpString,#position,1))<#asciiHiBound
THEN
CHAR(ASCII(SUBSTRING(#inpString,#position,1))+
(case when #ipOffset is null then
case when ASCII(SUBSTRING(#inpString,#position,1))%2=1 then #offsetAsciiDown1 else #offsetAsciiUp1 end
else #ipOffset*(-1) end))
ELSE ''
END
,'')
SELECT #position = #position + 1
END
select #maskedString
This uses rand with a seed like one of the other answers, but it is not necessary to provide a seed on every call. Providing it on the first call is sufficient.
This is my modified code.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND object_id = OBJECT_ID(N'usp_generateIdentifier'))
DROP PROCEDURE usp_generateIdentifier
GO
create procedure usp_generateIdentifier
#minLen int = 1
, #maxLen int = 256
, #seed int output
, #string varchar(8000) output
as
begin
set nocount on;
declare #length int;
declare #alpha varchar(8000)
, #digit varchar(8000)
, #specials varchar(8000)
, #first varchar(8000)
select #alpha = 'qwertyuiopasdfghjklzxcvbnm'
, #digit = '1234567890'
, #specials = '_##$&'
select #first = #alpha + '_#';
-- Establish our rand seed and store a new seed for next time
set #seed = (rand(#seed)*2147483647);
select #length = #minLen + rand() * (#maxLen-#minLen);
--print #length
declare #dice int;
select #dice = rand() * len(#first);
select #string = substring(#first, #dice, 1);
while 0 < #length
begin
select #dice = rand() * 100;
if (#dice < 10) -- 10% special chars
begin
select #dice = rand() * len(#specials)+1;
select #string = #string + substring(#specials, #dice, 1);
end
else if (#dice < 10+10) -- 10% digits
begin
select #dice = rand() * len(#digit)+1;
select #string = #string + substring(#digit, #dice, 1);
end
else -- rest 80% alpha
begin
select #dice = rand() * len(#alpha)+1;
select #string = #string + substring(#alpha, #dice, 1);
end
select #length = #length - 1;
end
end
go
In SQL Server 2012+ we could concatenate the binaries of some (G)UIDs and then do a base64 conversion on the result.
SELECT
textLen.textLen
, left((
select CAST(newid() as varbinary(max)) + CAST(newid() as varbinary(max))
where textLen.textLen is not null /*force evaluation for each outer query row*/
FOR XML PATH(''), BINARY BASE64
),textLen.textLen) as randomText
FROM ( values (2),(4),(48) ) as textLen(textLen) --define lengths here
;
If you need longer strings (or you see = characters in the result) you need to add more + CAST(newid() as varbinary(max)) in the sub select.
Here's one I came up with today (because I didn't like any of the existing answers enough).
This one generates a temp table of random strings, is based off of newid(), but also supports a custom character set (so more than just 0-9 & A-F), custom length (up to 255, limit is hard-coded, but can be changed), and a custom number of random records.
Here's the source code (hopefully the comments help):
/**
* First, we're going to define the random parameters for this
* snippet. Changing these variables will alter the entire
* outcome of this script. Try not to break everything.
*
* #var {int} count The number of random values to generate.
* #var {int} length The length of each random value.
* #var {char(62)} charset The characters that may appear within a random value.
*/
-- Define the parameters
declare #count int = 10
declare #length int = 60
declare #charset char(62) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
/**
* We're going to define our random table to be twice the maximum
* length (255 * 2 = 510). It's twice because we will be using
* the newid() method, which produces hex guids. More later.
*/
-- Create the random table
declare #random table (
value nvarchar(510)
)
/**
* We'll use two characters from newid() to make one character in
* the random value. Each newid() provides us 32 hex characters,
* so we'll have to make multiple calls depending on length.
*/
-- Determine how many "newid()" calls we'll need per random value
declare #iterations int = ceiling(#length * 2 / 32.0)
/**
* Before we start making multiple calls to "newid", we need to
* start with an initial value. Since we know that we need at
* least one call, we will go ahead and satisfy the count.
*/
-- Iterate up to the count
declare #i int = 0 while #i < #count begin set #i = #i + 1
-- Insert a new set of 32 hex characters for each record, limiting to #length * 2
insert into #random
select substring(replace(newid(), '-', ''), 1, #length * 2)
end
-- Now fill the remaining the remaining length using a series of update clauses
set #i = 0 while #i < #iterations begin set #i = #i + 1
-- Append to the original value, limit #length * 2
update #random
set value = substring(value + replace(newid(), '-', ''), 1, #length * 2)
end
/**
* Now that we have our base random values, we can convert them
* into the final random values. We'll do this by taking two
* hex characters, and mapping then to one charset value.
*/
-- Convert the base random values to charset random values
set #i = 0 while #i < #length begin set #i = #i + 1
/**
* Explaining what's actually going on here is a bit complex. I'll
* do my best to break it down step by step. Hopefully you'll be
* able to follow along. If not, then wise up and come back.
*/
-- Perform the update
update #random
set value =
/**
* Everything we're doing here is in a loop. The #i variable marks
* what character of the final result we're assigning. We will
* start off by taking everything we've already done first.
*/
-- Take the part of the string up to the current index
substring(value, 1, #i - 1) +
/**
* Now we're going to convert the two hex values after the index,
* and convert them to a single charset value. We can do this
* with a bit of math and conversions, so function away!
*/
-- Replace the current two hex values with one charset value
substring(#charset, convert(int, convert(varbinary(1), substring(value, #i, 2), 2)) * (len(#charset) - 1) / 255 + 1, 1) +
-- (1) -------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------------
-- (2) ---------------------------------^^^^^^^^^^^^^^^^^^^^^^11111111111111111111111^^^^-------------------------------------
-- (3) --------------------^^^^^^^^^^^^^2222222222222222222222222222222222222222222222222^------------------------------------
-- (4) --------------------333333333333333333333333333333333333333333333333333333333333333---^^^^^^^^^^^^^^^^^^^^^^^^^--------
-- (5) --------------------333333333333333333333333333333333333333333333333333333333333333^^^4444444444444444444444444--------
-- (6) --------------------5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555^^^^----
-- (7) ^^^^^^^^^^^^^^^^^^^^66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666^^^^
/**
* (1) - Determine the two hex characters that we'll be converting (ex: 0F, AB, 3C, etc.)
* (2) - Convert those two hex characters to a a proper hexadecimal (ex: 0x0F, 0xAB, 0x3C, etc.)
* (3) - Convert the hexadecimals to integers (ex: 15, 171, 60)
* (4) - Determine the conversion ratio between the length of #charset and the range of hexadecimals (255)
* (5) - Multiply the integer from (3) with the conversion ratio from (4) to get a value between 0 and (len(#charset) - 1)
* (6) - Add 1 to the offset from (5) to get a value between 1 and len(#charset), since strings start at 1 in SQL
* (7) - Use the offset from (6) and grab a single character from #subset
*/
/**
* All that is left is to add in everything we have left to do.
* We will eventually process the entire string, but we will
* take things one step at a time. Round and round we go!
*/
-- Append everything we have left to do
substring(value, 2 + #i, len(value))
end
-- Select the results
select value
from #random
It's not a stored procedure, but it wouldn't be that hard to turn it into one. It's also not horrendously slow (it took me ~0.3 seconds to generate 1,000 results of length 60, which is more than I'll ever personally need), which was one of my initial concerns from all of the string mutation I'm doing.
The main takeaway here is that I'm not trying to create my own random number generator, and my character set isn't limited. I'm simply using the random generator that SQL has (I know there's rand(), but that's not great for table results). Hopefully this approach marries the two kinds of answers here, from overly simple (i.e. just newid()) and overly complex (i.e. custom random number algorithm).
It's also short (minus the comments), and easy to understand (at least for me), which is always a plus in my book.
However, this method cannot be seeded, so it's going to be truly random each time, and you won't be able to replicate the same set of data with any means of reliability. The OP didn't list that as a requirement, but I know that some people look for that sort of thing.
I know I'm late to the party here, but hopefully someone will find this useful.
Based on various helpful responses in this article I landed with a combination of a couple options I liked.
DECLARE #UserId BIGINT = 12345 -- a uniqueId in my system
SELECT LOWER(REPLACE(NEWID(),'-','')) + CONVERT(VARCHAR, #UserId)
Below are the way to Generate 4 Or 8 Characters Long Random Alphanumeric String in SQL
select LEFT(CONVERT(VARCHAR(36),NEWID()),4)+RIGHT(CONVERT(VARCHAR(36),NEWID()),4)
SELECT RIGHT(REPLACE(CONVERT(VARCHAR(36),NEWID()),'-',''),8)
So I liked a lot of the answers above, but I was looking for something that was a little more random in nature. I also wanted a way to explicitly call out excluded characters. Below is my solution using a view that calls the CRYPT_GEN_RANDOM to get a cryptographic random number. In my example, I only chose a random number that was 8 bytes. Please note, you can increase this size and also utilize the seed parameter of the function if you want. Here is the link to the documentation: https://learn.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql
CREATE VIEW [dbo].[VW_CRYPT_GEN_RANDOM_8]
AS
SELECT CRYPT_GEN_RANDOM(8) as [value];
The reason for creating the view is because CRYPT_GEN_RANDOM cannot be called directly from a function.
From there, I created a scalar function that accepts a length and a string parameter that can contain a comma delimited string of excluded characters.
CREATE FUNCTION [dbo].[fn_GenerateRandomString]
(
#length INT,
#excludedCharacters VARCHAR(200) --Comma delimited string of excluded characters
)
RETURNS VARCHAR(Max)
BEGIN
DECLARE #returnValue VARCHAR(Max) = ''
, #asciiValue INT
, #currentCharacter CHAR;
--Optional concept, you can add default excluded characters
SET #excludedCharacters = CONCAT(#excludedCharacters,',^,*,(,),-,_,=,+,[,{,],},\,|,;,:,'',",<,.,>,/,`,~');
--Table of excluded characters
DECLARE #excludedCharactersTable table([asciiValue] INT);
--Insert comma
INSERT INTO #excludedCharactersTable SELECT 44;
--Stores the ascii value of the excluded characters in the table
INSERT INTO #excludedCharactersTable
SELECT ASCII(TRIM(value))
FROM STRING_SPLIT(#excludedCharacters, ',')
WHERE LEN(TRIM(value)) = 1;
--Keep looping until the return string is filled
WHILE(LEN(#returnValue) < #length)
BEGIN
--Get a truly random integer values from 33-126
SET #asciiValue = (SELECT TOP 1 (ABS(CONVERT(INT, [value])) % 94) + 33 FROM [dbo].[VW_CRYPT_GEN_RANDOM_8]);
--If the random integer value is not in the excluded characters table then append to the return string
IF(NOT EXISTS(SELECT *
FROM #excludedCharactersTable
WHERE [asciiValue] = #asciiValue))
BEGIN
SET #returnValue = #returnValue + CHAR(#asciiValue);
END
END
RETURN(#returnValue);
END
Below is an example of the how to call the function.
SELECT [dbo].[fn_GenerateRandomString](8,'!,#,#,$,%,&,?');
May this will be an answer to create random lower & upper characters. It's using a while loop which can be controlled to generate the string with a specific length.
--random string generator
declare #maxLength int = 5; --max length
declare #bigstr varchar(10) --uppercase character
declare #smallstr varchar(10) --lower character
declare #i int = 1;
While #i <= #maxLength
begin
set #bigstr = concat(#bigstr, char((rand()*26 + 65)));
set #smallstr = concat(#smallstr, char((rand()*26 + 96)));
set #i = len(#bigstr)
end
--select query
select #bigstr, #smallstr

How do I convert an int to a zero padded string in T-SQL?

Let's say I have an int with the value of 1. How can I convert that int to a zero padded string, such as 00000001?
Declare #MyInt integer Set #MyInt = 123
Declare #StrLen TinyInt Set #StrLen = 8
Select Replace(Str(#MyInt, #StrLen), ' ' , '0')
Another way is:
DECLARE #iVal int = 1
select REPLACE(STR(#iVal, 8, 0), ' ', '0')
as of SQL Server 2012 you can now do this:
format(#int, '0000#')
This work for me:
SELECT RIGHT('000' + CAST(Table.Field AS VARCHAR(3)),3) FROM Table
...
I created this user function
T-SQL Code :
CREATE FUNCTION CIntToChar(#intVal Int, #intLen Int) RETURNS nvarchar(24) AS BEGIN
IF #intlen > 24
SET #intlen = 24
RETURN REPLICATE('0',#intLen-LEN(RTRIM(CONVERT(nvarchar(24),#intVal))))
+ CONVERT(nvarchar(24),#intVal) END
Example :
SELECT dbo.CIntToChar( 867, 6 ) AS COD_ID
OUTPUT
000867
Use FORMAT(<your number>,'00000000') use as many zeroes as you need to have digits in your final outcome.
Here is official documentation of the FORMAT function
If I'm trying to pad to a specific total length, I use the REPLICATE and DATALENGTH functions, like so:
DECLARE #INT INT
DECLARE #UNPADDED VARCHAR(3)
DECLARE #PADDED VARCHAR(3)
SET #INT = 2
SET #UNPADDED = CONVERT(VARCHAR(3),#INT)
SET #PADDED = REPLICATE('0', 3 - DATALENGTH(#UNPADDED)) + #UNPADDED
SELECT #INT, #UNPADDED, #PADDED
I used variables here for simplicity, but you see, you can specify the final length of the total string and not worry about the size of the INT that you start with as long as it's <= the final string length.
I always use:
SET #padded = RIGHT('z0000000000000'
+ convert(varchar(30), #myInt), 8)
The z stops SQL from implicitly coverting the string into an int for the addition/concatenation.
If the int can go negative you have a problem, so to get around this I sometimes do this:
DECLARE #iVal int
set #iVal = -1
select
case
when #ival >= 0 then right(replicate('0',8) + cast(#ival as nvarchar(8)),8)
else '-' + right(replicate('0',8) + cast(#ival*-1 as nvarchar(8)),8)
end
Very straight forward way to think about padding with '0's is, if you fixed your #_int's to have 4 decimals, you inject 4 '0's:
select RIGHT( '0000'+ Convert(varchar, #_int), 4) as txtnum
; if your fixed space is 3, you inject 3'0's
select RIGHT( '000'+ Convert(varchar, #_int), 3) as txtnum
; below I inject '00' to generate 99 labels for each bldg
declare #_int int
set #_int = 1
while #_int < 100 Begin
select BldgName + '.Floor_' + RIGHT( '00'+ Convert(varchar, #_int), 2)
+ '.balcony' from dbo.tbl_FloorInfo group by BldgName
set #_int = #_int +1
End
Result is:
'BldgA.Floor_01.balcony'
'BldgB.Floor_01.balcony'
'BldgC.Floor_01.balcony'
..
..
'BldgA.Floor_10.balcony'
'BldgB.Floor_10.balcony'
'BldgC.Floor_10.balcony'
..
..
..
'BldgA.Floor_99.balcony'
'BldgB.Floor_99.balcony'
'BldgC.Floor_99.balcony'
Or if you really want to go hard-core... ;-)
declare #int int
set #int = 1
declare #string varchar(max)
set #string = cast(#int as varchar(max))
declare #length int
set #length = len(#string)
declare #MAX int
set #MAX = 8
if #length < #MAX
begin
declare #zeros varchar(8)
set #zeros = ''
declare #counter int
set #counter = 0
while (#counter < (#MAX - #length))
begin
set #zeros = #zeros + '0'
set #counter = #counter + 1
end
set #string = #zeros + #string
end
print #string
And then there's this one, using REPLICATE:
SELECT REPLICATE('0', 7) + '1'
Of course, you can replace the literals 7 and '1' with appropriate functions as needed; the above gives you your example. For example:
SELECT REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt)
will pad an integer of less than 8 places with zeros up to 8 characters.
Now, a negative number in the second argument of REPLICATE will return NULL. So, if that's a possibility (say, #myInt could be over 100 million in the above example), then you can use COALESCE to return the number without leading zeros if there are more than 8 characters:
SELECT COALESCE(REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt), CONVERT(nvarchar, #myInt))
I think Charles Bretana's answer is the simplest and fastest. A similar solution without using STR is:
SELECT REPLACE(REVERSE(
CONVERT(CHAR(5 /*<= Target length*/)
, REVERSE(CONVERT(VARCHAR(100), #MyInt)))
), ' ', '0')