I want convert my Hijri Shamsi date '92/2/3' to this format : '92/02/03'
With this code, I get this error :The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Declare #Str Varchar(10) = '92/2/3'
Select Convert(Varchar(10), Convert(DateTime, #Str), 111)
How can i change format of date ?
Since you don't have centuries you should use 11, not 111 as your conversion code
You need to use 11 in the inner convert to tell it what format it is converting FROM
Declare #Str Varchar(10) = '92/2/3'
Select Convert(Varchar(10), Convert(DateTime, #Str,11), 11)
Use this functions to convert Gregorian date to Hijri(Shamsi) date with your requested format:
CREATE FUNCTION [dbo].[ShamsiDate]
(
#ChirsDate SMALLDATETIME
)
RETURNS CHAR(10)
AS
BEGIN
DECLARE #SolarDate CHAR(10)
DECLARE #Day CHAR(2)
DECLARE #Mon CHAR(2)
DECLARE #SDay INT
DECLARE #SMon INT
DECLARE #SYear INT
SET #SYear = dbo.ShamsiDatePart(#ChirsDate, 'Y')
SET #SMon = dbo.ShamsiDatePart(#ChirsDate, 'M')
SET #SDay = dbo.ShamsiDatePart(#ChirsDate, 'D')
IF #SMon <= 9
SELECT #Mon = '0' + CONVERT(CHAR(1), #SMon)
ELSE
SELECT #Mon = CONVERT(CHAR(2), #SMon)
IF #SDay <= 9
SELECT #Day = '0' + CONVERT(CHAR(1), #SDay)
ELSE
SELECT #Day = CONVERT(CHAR(2), #SDay)
SELECT #SolarDate = CONVERT(CHAR(4), #SYear) + '/' + #Mon + '/'
+ #Day
RETURN #SolarDate
END
CREATE FUNCTION [dbo].[ShamsiDatePart]
(
#MiDate DATETIME ,
#ADatePart CHAR
)
RETURNS INT
AS
BEGIN
DECLARE #TmpY INT ,
#Leap INT
DECLARE #Sh_Y INT ,
#Sh_M INT ,
#Sh_D INT ,
#Result INT
IF #MiDate IS NULL
RETURN 0
DECLARE #Result INT
SET #Result = CONVERT(INT, CONVERT(FLOAT, #MiDate))
IF #Result <= 78
BEGIN
SET #Sh_Y = 1278
SET #Sh_M = ( #Result + 10 ) / 30 + 10
SET #Sh_D = ( #Result + 10 ) % 30 + 1
END
ELSE
BEGIN
SET #Result = #Result - 78
SET #Sh_Y = 1279
WHILE 1 = 1
BEGIN
SET #TmpY = #Sh_Y + 11
SET #TmpY = #TmpY - ( #TmpY / 33 ) * 33
IF ( #TmpY <> 32 )
AND ( ( #TmpY / 4 ) * 4 = #TmpY )
SET #Leap = 1
ELSE
SET #Leap = 0
IF #Result <= ( 365 + #Leap )
BREAK
SET #Result = #Result - ( 365 + #Leap )
SET #Sh_Y = #Sh_Y + 1
END
IF #Result <= 31 * 6
BEGIN
SET #Sh_M = ( #Result - 1 ) / 31 + 1
SET #Sh_D = ( #Result - 1 ) % 31 + 1
END
ELSE
BEGIN
SET #Sh_M = ( ( #Result - 1 ) - 31 * 6 ) / 30 + 7
SET #Sh_D = ( ( #Result - 1 ) - 31 * 6 ) % 30 + 1
END
END
RETURN CASE #ADatePart WHEN 'Y' THEN #Sh_Y WHEN 'M' THEN #Sh_M WHEN 'D' THEN #Sh_D ELSE 0 END
END
You can use the give below solution, if you are using SQL Server 2012.
Declare #Str varchar(10) = '92/2/3'
Select Format(Convert(Date, #Str,11),'yy/MM/dd')
Imran
Related
I came up on a problem. I am using CodeTo128B function in T-SQL. The problem that i came up with if I give a value to it that has white spaces in it and then give the result to SSRS report with a sAdC128c font the barcode can not be read (the devices that reads barcodes just does not recognize it because the barcode in the image is not in tact (it has spaces in between)
I've gathered up two values for a testing reference
SELECT [dbo].[CodeTo128B] ('1 TEST') AS [Column]
UNION
SELECT [dbo].[CodeTo128B] ('1TEST') AS [Column]
The problem is that the first barcode is not recognized by the reader (Android Cell phone app Barcode Scanner i think that this is because there is a space in a barcode but i can't seem to figure out what is wrong with this function why it does not recognize spaces? As i see the ASCII values are also different because of the space (Column values)
Any ideas ? Any help would be very much appreciated
ALTER FUNCTION [dbo].[CodeTo128B] (#myString varchar(255))
RETURNS VARCHAR(255) AS
BEGIN
-- Define the string of characters that we'll need to pull the reference of
declare #asciiString varchar(255)
select #asciiString = ' !"#$%&''()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
select #asciiString = #asciiString + char(195) -- 0xC3
select #asciiString = #asciiString + char(196) -- 0xC4
select #asciiString = #asciiString + char(197) -- 0xC5
select #asciiString = #asciiString + char(198) -- 0xC6
select #asciiString = #asciiString + char(199) -- 0xC7
select #asciiString = #asciiString + char(200) -- 0xC8
select #asciiString = #asciiString + char(201) -- 0xC9
select #asciiString = #asciiString + char(202) -- 0xCA
-- Define the stop and start characters
declare #stopchar char(1)
declare #startchar char(1)
declare #spacechar char(1)
select #stopchar = char(206) -- 0xCE
select #startchar = char(204) -- 0xCC
select #spacechar = char(194) -- 0xC2
-- Define the final holding place of our output string
declare #finalArray varchar(255)
-- Define the variables that we'll need to be using
declare #checksumTotal int
declare #checksum int
select #checksumTotal = 104;
select #checksum = 0;
-- Start building our output
select #finalArray = #startchar
-- Loop through our input variable and start pulling out stuff
declare #position int
declare #thisChar char(1)
select #position = 1
while #position <= len(#myString)
begin
select #thisChar = substring(#myString, #position, 1)
select #checksumTotal = #checksumTotal + (#position * (ascii(#thischar)-32))
select #finalArray = #finalArray + #thisChar
select #position = #position + 1
end -- We've gone past the length now
-- Now we need to figure out and add the checksum character
select #checksum = #checksumTotal % 103
if #checksum = 0
select #finalArray = #finalArray + #spacechar
else
-- Barcorde array assumes 0 as initial offset so we need to add 1 to checksum
select #finalArray = #finalArray + substring(#asciiString, #checksum+1, 1)
-- Now we append the stop character
select #finalArray = #finalArray + #stopchar
-- The #final Array represents the barcode encoded string
return #finalArray
END
Figured out the solution on my own. Just rewrote the function to recalculate when a empty value is passed and fill the empty space in the formed string
Code reference displayed bellow
Happy coding :)
CREATE FUNCTION [dbo].[CodeTo128B]
(
#Barcode VARCHAR(20)
)
RETURNS VARCHAR(20)
BEGIN
DECLARE #site_value INT;
SET #site_value =1;
DECLARE #v_data_to_encode varchar(4000)
DECLARE #check_digit_char varchar(1)
DECLARE #check_digit BIGINT
DECLARE #start_character varchar(1)
DECLARE #stop_character varchar(1)
DECLARE #current_value bigint
DECLARE #encoded_string varchar(1000)
DECLARE #weight_total BIGINT
DECLARE #mrLen BIGINT
SET #v_data_to_encode = UPPER(#Barcode)
SET #start_character = CHAR(0203)
SET #stop_character = CHAR(0206)
SET #weight_total = ASCII(#start_character) - 100
SET #mrLen = LEN(#v_data_to_encode)
WHILE #site_value <= #mrLen
BEGIN
SET #current_value = CAST(ASCII(SUBSTRING (#v_data_to_encode, #site_value, 1)) AS BIGINT)
if #current_value < 135
set #current_value = #current_value - 32
ELSE if #current_value >= 135
set #current_value = #current_value - 100
SET #current_value = #current_value * #site_value
SET #weight_total = #weight_total + #current_value
set #site_value = #site_value+1
END
SET #check_digit = (#weight_total % 103)
BEGIN
if #check_digit < 95 and #check_digit > 0
SET #check_digit_char = CHAR(#check_digit + 32)
ELSE if #check_digit >= 95
SET #check_digit_char = char(#check_digit + 100)
ELSE if #check_digit = 0
SET #check_digit_char = char(194);
END
SET #encoded_string = replace(#v_data_to_encode,' ',char(194))
return CONCAT (#start_character,#encoded_string,#check_digit_char,#stop_character)
end
I've started drafting a scalar function in SSMS 2012 to take a string and swap any occurrence of 3 hex URL characters (%2b, %2f and %3d) with their respective single character (-, / and =):
DECLARE #OutputText as VARCHAR(100)
DECLARE #c as Int
DECLARE #cIn as CHAR(3)
DECLARE #cOut as CHAR(1)
DECLARE #s as Int
SET #OutputText = '%2bBWCq6sE7OU%3d'
SET #c = 1
WHILE #c <= 3
BEGIN
-- Set the search/replace characters depending on iteration
IF #c = 1
SET #cIn = '%2b'
SET #cOut = '-';
IF #c = 2
SET #cIn = '%2f'
SET #cOut = '/';
IF #c = 3
SET #cIn = '%3d'
SET #cOut = '=';
SET #s = PATINDEX('%' + #cIn +'%', #OutputText)
WHILE #s > 0
BEGIN
PRINT 'Character Loop: ' + CAST(#c as VARCHAR(1)) + ' | looking for ' + #cIn + ' within ' + #OutputText
PRINT '(Replace ' + #cIn + ' with ' + #cOut + ')'
PRINT '-- ' + #cIn + ' found at position: ' + CAST(#s as VARCHAR(2))
SET #OutputText = STUFF(#OutputText, PATINDEX('%' + #cIn +'%', #OutputText) - 1, 3, #cOut)
PRINT '>> OutputText now: ' + #OutputText + CHAR(10)
SET #s = PATINDEX('%' + #cIn +'%', #OutputText)
END
SET #c = #c + 1
END
PRINT 'Final output: ' + #OutputText
The various PRINTs return this:
Notice the first character loop output says Replace %2b with = ... yet the if statement should be setting #cOut to - not = when #c = 1.
Another minor issue is that where the output says %2b found at position: the position number given seems 1 higher than it should be, like it's ignoring % of #cIn.
In your If statements, each setting of #cout will happen because they are not part of the IF. Only the next line after the IF executes. You need to wrap them in Begin End:
IF #c = 1
begin
SET #cIn = '%2b'
SET #cOut = '-'
end
else IF #c = 2
begin
SET #cIn = '%2f'
SET #cOut = '/'
end
else IF #c = 3
begin
SET #cIn = '%3d'
SET #cOut = '='
end
To prove this:
declare #thing int = 2
if #thing=1
select 'ralph'
select 'charles'
if #thing = 2
select 'ralph2'
select 'charles2'
This will produce charles, ralph2, charles2
Whereas this (with begin end):
declare #thing int = 2
if #thing=1
begin
select 'ralph'
select 'charles'
end
if #thing = 2
begin
select 'ralph2'
select 'charles2'
end
will correctly produce ralph2, charles2
How to generate a matrix of random numbers where the values in each row add up to X in T-SQL?
The solution matrix should be dynamic:
User can specify number of columns to be returned in the result
User can specify number of rows to be returned in the result
Each row must sum to X (eg. 1)
create proc RandomNumberGenerator
(
#rows int
, #cols int
, #rowsumtotal float
)
as
....
First create a UDF...
CREATE FUNCTION [dbo].[_ex_fn_SplitToTable] (#str varchar(5000), #sep varchar(1) = null)
RETURNS #ReturnVal table (n int, s varchar(5000))
AS
/*
Alpha Test
-----------
select * from [dbo].[_ex_fn_SplitToTable_t2]('a b c d e',' ')
*/
BEGIN
if #sep = ' '
begin
set #sep = CHAR(167)
set #str = REPLACE(#str,' ',CHAR(167))
end
declare #str2 varchar(5000)
declare #sep2 varchar(1)
if LEN(ISNULL(#sep,'')) = 0
begin
declare #i int
set #i = 0
set #str2 = ''
declare #char varchar(1)
startloop:
set #i += 1
--print #i
set #char = substring(#str,#i,1)
set #str2 = #str2 + #char + ','
if LEN(#str) <= #i
goto exitloop
goto startloop
exitloop:
set #str2 = left(#str2,LEN(#str2) - 1)
set #sep2 = ','
--print #str2
end
else
begin
set #str2 = #str
set #sep2 = #sep
end
;WITH Pieces(n, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep2, #str2)
UNION ALL
SELECT n + 1, stop + 1, CHARINDEX(#sep2, #str2, stop + 1)
FROM Pieces
WHERE stop > 0
)
insert into #ReturnVal(n,s)
SELECT n,
SUBSTRING(#str2, start, CASE WHEN stop > 0 THEN stop-start ELSE 5000 END) AS s
FROM Pieces option (maxrecursion 32767)
RETURN
END
GO
Then, create this stored proc...
CREATE PROC [dbo].[RandomNumberGenerator]
(
#Pockets int = 6,
#SumTo float = 100,
#i_iterations int = 100
)
/*
ALPHA TEST
----------
exec RandomNumberGenerator 10, 100, 500
*/
AS
if object_id('tempdb..#_Random_00') is not null drop table #_Random_00
declare #columnstring varchar(max) = (SELECT REPLICATE('c ',#Pockets) as Underline)
print #columnstring
if object_id('tempdb..#_Random_columns') is not null drop table #_Random_columns
select s+CONVERT(varchar,dbo.PadLeft(convert(varchar,n),'0',3)) cols
into #_Random_columns
from [dbo].[_ex_fn_SplitToTable](#columnstring,' ') where LEN(s) > 0
-- ===========================
--select * from #_Random_columns
-- ===========================
declare #columns_sql varchar(max)
set #columns_sql =
(
select distinct
stuff((SELECT distinct + cast(cols as varchar(50)) + ' float, '
FROM (
select cols
from #_Random_columns
) t2
--where t2.n = t1.n
FOR XML PATH('')),3,0,'')
from (
select cols
from #_Random_columns
) t1
)
set #columns_sql = LEFT(#columns_sql,LEN(#columns_sql) - 1)
print #columns_sql
declare #sql varchar(max)
set #sql = 'if object_id(''tempdb..##_proctable_Random_01'') is not null drop table ##_proctable_Random_01 '
print #sql
execute(#sql)
set #sql = 'create table ##_proctable_Random_01 (rowid int,' + #columns_sql + ')'
print #sql
execute(#sql)
declare #TotalOfRand float
declare #i_inner int
declare #i_outer int
set #i_outer = 0
start_outer:
set #i_outer = #i_outer + 1
set #i_inner = 0
declare #sumstring varchar(max)
set #sumstring = ''
start_inner:
set #i_inner = #i_inner+1
set #sumstring = #sumstring + CONVERT(varchar, rand()) + ','
if #i_inner >= #Pockets
goto exit_inner
goto start_inner
exit_inner:
set #TotalOfRand = ( select sum(convert(float,s)) from dbo._ex_fn_SplitToTable(#sumstring,',') )
declare #sumstring_quotient varchar(max)
set #sumstring_quotient = replace(#sumstring,',', '/' + Convert(varchar,#TotalOfRand) + '*' + convert(varchar,#SumTo) + ',')
set #sumstring_quotient = LEFT(#sumstring_quotient,len(#sumstring_quotient) - 1)
print #sumstring_quotient
set #sql = '
insert into ##_proctable_Random_01
select
( select count(*) + 1 from ##_proctable_Random_01 ) rowid,' + #sumstring_quotient
execute(#sql)
if #i_outer >= #i_iterations
goto exit_outer
goto start_outer
exit_outer:
select * from ##_proctable_Random_01
drop table ##_proctable_Random_01
GO
I have an asp.net application that uses SQL Server 2005. In this application I want to create a function that returns unique reference numbers for new Inquiry Id.
I read about UNIQUEIDENTIFIER but it has a specific format like 1548C3E02-2D73-4244-8787-D45AC590519A.
I want output like 1703-HJIF-2012. Here first have combination of current datepart like date and month, second is random string which auto generate and third one is year part of current date. I don't have any idea how I could create such a function and how I would be calling this function from a stored procedure and get result string from function with this required format.
here some one posted me this function but this generates spaces instead of 0 :
create function UniqueRefNum (#r1 float, #r2 float, #r3 float, #r4 float)
returns char(14)
begin
-- Not sure if rand() might return 1.0
-- If it does, the conversion code below would produce a character that's not an
-- uppercase letter so let's avoid it just in case
if #r1 = 1.0 set #r1 = 0
if #r2 = 1.0 set #r2 = 0
if #r3 = 1.0 set #r3 = 0
if #r4 = 1.0 set #r4 = 0
declare #now datetime
set #now = getdate() -- or getutcdate()
declare #m char(2)
if month(#now) < 10
set #m = '0' + month(#now)
else
set #m = month(#now)
declare #d char(2)
if day(#now) < 10
set #d = '0' + day(#now)
else
set #d = day(#now)
return #m + #d + '-' +
char(65 + cast(#r1 * 26 as int)) +
char(65 + cast(#r2 * 26 as int)) +
char(65 + cast(#r3 * 26 as int)) +
char(65 + cast(#r4 * 26 as int)) +
'-' + cast(year(#now) as varchar)
end
You then call the function from your stored procedure like this:
declare #uniqueRef char(14)
set #uniqueRef = dbo.UniqueRefNum(rand(), rand(), rand(), rand())
---------------Updated-----------------------------
it's generates out put is like that :
4 24-HHBH-2014
and i want output something like this :
2404-HHBH-2014
DDMM-XXXX-YYYY
You need to cast the day/month values to char before concatenating the strings.
declare #m char(2)
if month(#now) < 10
set #m = '0' + cast(month(#now) as char(1))
else
set #m = month(#now)
declare #d char(2)
if day(#now) < 10
set #d = '0' + cast(day(#now) as char(1))
else
set #d = day(#now)
The thing is that the string in '0' + month(#now) is converted to integer and then the two numbers are added up.
I have a DateTime column row and I declare a date string:
Row:
2010-08-27 13:45:55
My string:
'2010-08-27'
How can I check if that string is in that row ?
I tried the following query:
declare #year as nvarchar(4)
declare #month as nvarchar(2)
declare #day as nvarchar(2)
set #year = '2010'
set #month = '08'
set #day = '23'
select * FROM [dbo].[customer_import] CsrImport
where
(YEAR(CsrImport.import_date) = #year
AND MONTH(CsrImport.import_date) = #month
AND DAY(CsrImport.import_date) = #day)
but I see that it returns all rows (even that are not contains that date)
Sql server : ISDATE (Transact-SQL)
----Invalid date
SELECT ISDATE('30/2/2007')
RETURNS : 0 (Zero)
----Valid date
SELECT ISDATE('12/12/20007)'
RETURNS : 1 (ONE)
----Invalid DataType
SELECT ISDATE('SQL')
RETURNS : 0 (Zero)
Like this, this will also be able to use the index, do not use function on the column itself..it is not SARGable!!
where import_date >= convert(datetime,#year + #month + #day)
and import_date < convert(datetime,#year + #month + #day) + 1
The best way for you would be to use dates and not 3 different parameters, what if someone passes in 13 for month?
Here is an example which checks that the values that are passed in can be converted to a date, if not it will show an error message
DECLARE #year AS NVARCHAR(4)
DECLARE #month AS NVARCHAR(2)
DECLARE #day AS NVARCHAR(2)
SET #year = '2010'
SET #month = '08'
SET #day = '23'
DECLARE #date DATETIME
IF ISDATE(#year + #month + #day) = 0
BEGIN
RAISERROR('values passed in are not a valid date',16,1)
RETURN
END
ELSE
BEGIN
SET #date = #year + #month + #day
END
SELECT * FROM [dbo].[customer_import] CsrImport
WHERE import_date >=#date
AND import_date < #date + 1
That should work, howabout if you make the values INTS
declare #year as INT
declare #month as INT
declare #day as INT
set #year = 2010
set #month = 08
set #day = 23
select * FROM [dbo].[customer_import] CsrImport
where
(YEAR(CsrImport.import_date) = #year
AND MONTH(CsrImport.import_date) = #month
AND DAY(CsrImport.import_date) = #day)
EDIT: Make sure all the statement is highlighted when you run it too. As simple as it seems, is it possible you mised the where clause if you highlighted the statement.
Just turn the datestring into a date (or datetime) variable and use a where clause:
Since your table has times in it, you have to strip them out or compare them to the midnioght before and after
Declare #myDate DateTime
Set #myDate = 'August 23 2010'
Select * FROM [dbo].[customer_import] CsrImport
Where DateDiff(day, myDate,import_date) = 0 -- Not Sargable
or
Declare #myDate DateTime
Set #myDate = 'August 23 2010'
Select * FROM [dbo].[customer_import] CsrImport
Where import_date) Between #mydate And #Mydate + 1 -- Sargable