How to convert datetime in Persian in SQL Server - sql-server

I want to convert my datetime into Persian datetime in SQL Server. My datetime is in MM/DD/YYYY format. Is there any function in SQL Server to do this as when I want hijri datetime I use this
SELECT CONVERT(VARCHAR(40), GETDATE(), 131) -- Output is 14/08/1432 5:02:01:197PM
I'm using SQL Server 2008.

Best method in SQL Server 2016
Example:
SELECT FORMAT(GETDATE(), 'yyyy/MM/dd-HH:mm:ss', 'fa')
Answer:
1398/10/08-05:37:59

I know it is too late for answering this question, but I've submitted the function that I'm using for a long time without any bug, all of other methods which I've ever seen have problem with intercalary years:
CREATE FUNCTION [CalculatePersianDate] ( #intDate DATETIME )
RETURNS NVARCHAR(max)
BEGIN
DECLARE #shYear AS INT ,#shMonth AS INT ,#shDay AS INT ,#intYY AS INT ,#intMM AS INT ,#intDD AS INT ,#Kabiseh1 AS INT ,#Kabiseh2 AS INT ,#d1 AS INT ,#m1 AS INT, #shMaah AS NVARCHAR(max),#shRooz AS NVARCHAR(max),#DayCnt AS INT
DECLARE #DayDate AS NVARCHAR(max)
SET #intYY = DATEPART(yyyy, #intDate)
IF #intYY < 1000 SET #intYY = #intYY + 2000
SET #intMM = MONTH(#intDate)
SET #intDD = DAY(#intDate)
SET #shYear = #intYY - 622
SET #DayCnt = 5
IF ( ( #intYY - 1992 ) % 4 = 0) SET #Kabiseh1 = 0 ELSE SET #Kabiseh1 = 1
IF ( ( #shYear - 1371 ) % 4 = 0) SET #Kabiseh2 = 0 ELSE SET #Kabiseh2 = 1
SET #m1 = 1
SET #d1 = 1
SET #shMonth = 10
SET #shDay = 11
IF ( ( #intYY - 1993 ) % 4 = 0 ) SET #shDay = 12
WHILE ( #m1 != #intMM ) OR ( #d1 != #intDD )
BEGIN
SET #d1 = #d1 + 1
SET #DayCnt = #DayCnt + 1
IF
(#d1 = 32 AND (#m1 = 1 OR #m1 = 3 OR #m1 = 5 OR #m1 = 7 OR #m1 = 8 OR #m1 = 10 OR #m1 = 12))
OR
(#d1 = 31 AND (#m1 = 4 OR #m1 = 6 OR #m1 = 9 OR #m1 = 11))
OR
(#d1 = 30 AND #m1 = 2 AND #Kabiseh1 = 1)
OR
(#d1 = 29 AND #m1 = 2 AND #Kabiseh1 = 0)
BEGIN
SET #m1 = #m1 + 1
SET #d1 = 1
END
IF #m1 > 12
BEGIN
SET #intYY = #intYY + 1
SET #m1 = 1
END
IF #DayCnt > 7 SET #DayCnt = 1
SET #shDay = #shDay + 1
IF
(#shDay = 32 AND #shMonth < 7)
OR
(#shDay = 31 AND #shMonth > 6 AND #shMonth < 12)
OR
(#shDay = 31 AND #shMonth = 12 AND #Kabiseh2 = 1)
OR
(#shDay = 30 AND #shMonth = 12 AND #Kabiseh2 = 0)
BEGIN
SET #shMonth = #shMonth + 1
SET #shDay = 1
END
IF #shMonth > 12
BEGIN
SET #shYear = #shYear + 1
SET #shMonth = 1
END
END
IF #shMonth=1 SET #shMaah=N'فروردین'
IF #shMonth=2 SET #shMaah=N'اردیبهشت'
IF #shMonth=3 SET #shMaah=N'خرداد'
IF #shMonth=4 SET #shMaah=N'تیر'
IF #shMonth=5 SET #shMaah=N'مرداد'
IF #shMonth=6 SET #shMaah=N'شهریور'
IF #shMonth=7 SET #shMaah=N'مهر'
IF #shMonth=8 SET #shMaah=N'آبان'
IF #shMonth=9 SET #shMaah=N'آذر'
IF #shMonth=10 SET #shMaah=N'دی'
IF #shMonth=11 SET #shMaah=N'بهمن'
IF #shMonth=12 SET #shMaah=N'اسفند'
IF #DayCnt=1 SET #shRooz=N'شنبه'
IF #DayCnt=2 SET #shRooz=N'یکشنبه'
IF #DayCnt=3 SET #shRooz=N'دوشنبه'
IF #DayCnt=4 SET #shRooz=N'سه‌شنبه'
IF #DayCnt=5 SET #shRooz=N'چهارشنبه'
IF #DayCnt=6 SET #shRooz=N'پنجشنبه'
IF #DayCnt=7 SET #shRooz=N'جمعه'
--SET #DayDate = #shRooz + " " + LTRIM(STR(#shDay,2)) + " " + #shMaah + " " + STR(#shYear,4)
--پنجشنبه 17 اردیبهشت 1394
/*
SET #DayDate = LTRIM(STR(#shDay,2)) + " " + #shMaah + " " + STR(#shYear,4)
--17 اردیبهشت 1394
SET #DayDate = STR(#shYear,4) + "/"+LTRIM(STR(#shMonth,2)) + "/" + LTRIM(STR(#shDay,2))
--1394/2/17
--1394/02/17
*/
SET #DayDate = REPLACE(RIGHT(STR(#shYear, 4), 4), ' ', '0') + '/'+ REPLACE(STR(#shMonth, 2), ' ', '0') + '/' + REPLACE(( STR(#shDay,2) ), ' ', '0')
RETURN #DayDate
END
It is really easy to customize the result of the function.
adopted from: this page

I know it is too late but maybe useful for others like me having this trouble.
You should write a SQL Function for this conversion like this:
Converting Gregorian to Persian Date
and then use it like this:
SELECT dbo.[UDF_Gregorian_To_Persian]('2013-08-24')

Try this:
select format(getdate() , 'yyyy/MM/dd', 'fa-ir')

You can use the following code to convert the date. This practical and important method has been added to the 2012 version of SQL and can be used.
SELECT FORMAT(GETDATE(), 'yyyy/MM/dd-HH:mm:ss', 'fa')
Result: 1400/02/08-05:08:51
SELECT cast( FORMAT(GETDATE(), 'yyyyMMdd', 'fa') as int)
Result: 14000208
And you can use Format as Follow to get Higri Date:
SELECT FORMAT(GETDATE(), N'yyyy/MM/dd', N'ar')
Result: 1443/06/19

Out of the box, no.
You'd have to write your own UDF, however there is one on CodePlex and another

I believe the best available solution is to use SQLCLR-Jalali-Date-Utility. It has a straightforward installation guide and easy to use functions. Moreover, you can define the format of the converted date without any limitation. in fact, you can use the standard time formatting to define the shape of converted dates.
There are several examples provided inside the GitHub page.
select dbo.GregorianToJalali(GETDATE(),'yyyy/MM/dd hh:mm:ss tt') -- returns 1395/07/01 03:04:33 ب ظ

this is persian Calendar function in SQL 2016+
ALTER FUNCTION [dbo].[PCalendar](#date datetime)
RETURNS #ret TABLE (
ly int,
y int,
m int,
mname nvarchar(15),
d int,
dy int,
dw int,
dname nvarchar(10),
hh int,
mm int,
ss int,
mss int,
dt datetime,
t nvarchar(3))
as
BEGIN
DECLARE #format varchar(19);
set #format = 'yyyy/MM/dd HH:mm:ss';
DECLARE #y int;
DECLARE #m int;
DECLARE #d int;
DECLARE #dy int;
DECLARE #dw int;
DECLARE #hh int;
DECLARE #mm int;
DECLARE #ss int;
DECLARE #ms int;
DECLARE #ldt varchar(8);
set #y = DATEPART(YEAR, FORMAT(#date, #format, 'fa')) ;
set #m = DATEPART(MONTH, FORMAT(#date, #format, 'fa'));
set #d = DATEPART(DAY, FORMAT(#date, #format, 'fa')) ;
set #dy = DATEPART(DAYOFYEAR, FORMAT(#date, #format, 'fa'));
set #dw = DATEPART(WEEKDAY, FORMAT(#date,#format, 'fa'));
set #hh = DATEPART(HOUR, #date) ;
set #mm = DATEPART(MINUTE, #date) ;
set #ss = DATEPART(SECOND, #date);
set #ms = DATEPART(MILLISECOND, #date);
set #ldt =DATEPART(year, FORMAT(#date, #format, 'en'));
DECLARE #_w nvarchar(10);
set #_w = CASE
WHEN #dw=1 THEN N'جمعه'
WHEN #dw=2 THEN N'شنبه'
WHEN #dw=3 THEN N'یکشنبه'
WHEN #dw=4 THEN N'دوشنبه'
WHEN #dw=5 THEN N'سه شنبه'
WHEN #dw=6 THEN N'چهارشنبه'
ELSE N'پنج شنبه'
END;
DECLARE #_m nvarchar(15);
set #_m = CASE
WHEN #m=1 THEN N'فروردین'
WHEN #m=2 THEN N'اردیبهشت'
WHEN #m=3 THEN N'خرداد'
WHEN #m=4 THEN N'تیر'
WHEN #m=5 THEN N'مرداد'
WHEN #m=6 THEN N'شهریور'
WHEN #m=7 THEN N'مهر'
WHEN #m=8 THEN N'آبان'
WHEN #m=9 THEN N'آذر'
WHEN #m=10 THEN N'دی'
WHEN #m=11 THEN N'بهمن'
ELSE N'اسفند'
END;
set #_m = #_m+N' ماه';
INSERT INTO #ret
SELECT
IIF(#y % 33 in (1,5,9,13,17,22,26,30) , 1 , 0) as ly,
#y as y,
#m as m,
#_m as mname,
#d as d,
#dy as dy,
#dw as dw,
#_w as dname,
#hh as hh,
#mm as mm,
#ss as ss,
#ms as mss,
#date as dt,
IIF(#hh > 12 , N'ب.ظ','ق.ظ') as t;
RETURN;
END

You can convert it to shamsi using this functions.
The first function.
CREATE FUNCTION [dbo].[ToPersianDate](#dt [datetime])
RETURNS [nvarchar](10) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [PersianSQLFunctions].[UserDefinedFunctions].[ToPersianDate]
GO
second function.
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE FUNCTION [dbo].[ToPersianDate](#dt [datetime])
RETURNS [nvarchar](10) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [PersianSQLFunctions].[UserDefinedFunctions].[ToPersianDate]
GO
third function.
CREATE FUNCTION [dbo].[fnToShamsiDate]
(
#d DateTime
)
RETURNS NVARCHAR(10)
AS
BEGIN
-- Declare the return variable here
DECLARE #RV NVARCHAR(10)
IF (#d) IS NULL RETURN NULL;
ELSE SELECT #RV = DBO.ToPersianDate(#D);
-- Return the result of the function
RETURN #RV
END
GO
And also you can find shamsi months from this function
create function [dbo].[fnGetShamsiMonth]
(
#GregorianDate date
)
returns nvarchar(2)
as
begin
declare #ShamsiMonth nvarchar(2), #ShamsiDate nvarchar(10);
set #ShamsiDate = confsys.dbo.fnToShamsiDate(#GregorianDate);
set #ShamsiMonth = SUBSTRING(#ShamsiDate,6,2);
return #ShamsiMonth
end
GO
examples
select confsys.dbo.fnToShamsiDate(getdate())
result is 1397/12/29
get shamsi months
select confsys.dbo.fnGetShamsiMonth(GETDATE());

Function : Full Convert Persian (Shamsi / Jalali ) String to Gregorian (miladi) Datetime in sql server :
> create or ALTER Function [dbo].[Func_ShamsiToMiladi] (#Date
> Varchar(23) ) RETURNS DateTime BEGIN
> -- ==============================================================
> -- SELECT [dbo].[Func_ShamsiToMiladi] ('1356-09-20 05:35:00.000')
> --
> -- Output : '1977-12-11 02:05:00.000'
> -- ==============================================================
> -- BY: Shahrokh Vazifedan Hobabname#Gmail.COM DECLARE #PersianDate Varchar(23) SET #PersianDate = #Date
>
> DECLARE #Year INT = SUBSTRING(#PersianDate, 1, 4)
> DECLARE #Month INT = SUBSTRING(#PersianDate, 6, 2)
> DECLARE #Day INT = SUBSTRING(#PersianDate, 9, 2)
> DECLARE #DiffYear INT = #Year - 1350
> DECLARE #Time varchar(13) = SUBSTRING(#PersianDate, 11, 13)
>
>
> DECLARE #Days INT = #DiffYear * 365.24 +
> CASE WHEN #Month < 7 THEN (#Month - 1) * 31
> ELSE 186 + (#Month - 7) * 30 END + #Day
>
> DECLARE #StartDate DATETIME = '03/21/1971'
> DECLARE #ResultDate DATE = #StartDate + #Days
>
> DECLARE #TempDate varchar(23) = Convert( Nvarchar(10) , #ResultDate ,120) + #Time DECLARE #OffSET_First_half_in_Year
> INT; SET #OffSET_First_half_in_Year = iif( Substring(Convert(
> Nvarchar(50), #TempDate,120) ,6,16) Between '03-20 20:30' and '09-22
> 20:30' , -60 ,0)
> RETURN dateadd(MINUTE, #OffSET_First_half_in_Year + (-1)*datediff(MINUTE, getutcdate(), getdate()),#TempDate ) END
Created By : Shahrokh Vazifedan -Sari # Iran :)
Email: HobabName#Gmail.com

CREATE FUNCTION [dbo].[MITSH] (#MDate DateTime)
RETURNS Varchar(10)
AS
BEGIN
DECLARE #SYear as Integer
DECLARE #SMonth as Integer
DECLARE #my_mah varchar(2)
declare #my_day varchar(2)
DECLARE #SDay as Integer
DECLARE #AllDays as float
DECLARE #ShiftDays as float
DECLARE #OneYear as float
DECLARE #LeftDays as float
DECLARE #YearDay as Integer
DECLARE #Farsi_Date as Varchar(100)
SET #MDate=#MDate-CONVERT(char,#MDate,114)
SET #ShiftDays=466699 +2
SET #OneYear= 365.24199
SET #SYear = 0
SET #SMonth = 0
SET #SDay = 0
SET #AllDays = CAst(#Mdate as Real)
SET #AllDays = #AllDays + #ShiftDays
SET #SYear = (#AllDays / #OneYear) --trunc
SET #LeftDays = #AllDays - #SYear * #OneYear
if (#LeftDays < 0.5)
begin
SET #SYear=#SYear+1
SET #LeftDays = #AllDays - #SYear * #OneYear
end;
SET #YearDay = #LeftDays --trunc
if (#LeftDays - #YearDay) >= 0.5
SET #YearDay=#YearDay+1
if ((#YearDay / 31) > 6 )
begin
SET #SMonth = 6
SET #YearDay=#YearDay-(6 * 31)
SET #SMonth= #SMonth+( #YearDay / 30)
if (#YearDay % 30) <> 0
SET #SMonth=#SMonth+1
SET #YearDay=#YearDay-((#SMonth - 7) * 30)
end
else
begin
SET #SMonth = #YearDay / 31
if (#YearDay % 31) <> 0
SET #SMonth=#SMonth+1
SET #YearDay=#YearDay-((#SMonth - 1) * 31)
end
SET #SDay = #YearDay
SET #SYear=#SYear+1
if #SMonth <10 begin
set #my_mah='0'+str(#SMonth,1)
end else begin
set #my_mah = str(#SMonth,2)
end
if #sday <10 begin
set #my_day='0'+str(#Sday,1)
end else begin
set #my_day = str(#Sday,2)
end
SET #Farsi_Date = CAST (#SYear as VarChar(10)) + '/' + #my_mah + '/' + #my_day
Return #Farsi_Date
END
AN FOR EXEC FUNCTION
SELECT DBO.MITSH(GETDATE())
for example date is 2020-09-25
resualt =>>>> 1399/07/04

Complete Function For Shamsi date for SQL 2008 and 2008 R2 and below versions:
CREATE FUNCTION [dbo].[PersToJul](#iYear int,#iMonth int,#iDay int)
RETURNS bigint
AS
Begin
Declare #PERSIAN_EPOCH as int
Declare #epbase as bigint
Declare #epyear as bigint
Declare #mdays as bigint
Declare #Jofst as Numeric(18,2)
Declare #jdn bigint
Set #PERSIAN_EPOCH=1948321
Set #Jofst=2415020.5
If #iYear>=0
Begin
Set #epbase=#iyear-474
End
Else
Begin
Set #epbase = #iYear - 473
End
set #epyear=474 + (#epbase%2820)
If #iMonth<=7
Begin
Set #mdays=(Convert(bigint,(#iMonth) - 1) * 31)
End
Else
Begin
Set #mdays=(Convert(bigint,(#iMonth) - 1) * 30+6)
End
Set #jdn =Convert(int,#iday) + #mdays+ Cast(((#epyear * 682) - 110) / 2816 as int) + (#epyear - 1) * 365 + Cast(#epbase / 2820 as int) * 1029983 + (#PERSIAN_EPOCH - 1)
RETURN #jdn
End
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
CREATE FUNCTION [dbo].[GrToPers] (#date datetime)
Returns nvarchar(50)
AS
Begin
Declare #depoch as bigint
Declare #cycle as bigint
Declare #cyear as bigint
Declare #ycycle as bigint
Declare #aux1 as bigint
Declare #aux2 as bigint
Declare #yday as bigint
Declare #Jofst as Numeric(18,2)
Declare #jdn bigint
Declare #iYear As Integer
Declare #iMonth As Integer
Declare #iDay As Integer
Set #Jofst=2415020.5
Set #jdn=Round(Cast(#date as int)+ #Jofst,0)
Set #depoch = #jdn - [dbo].[PersToJul](475, 1, 1)
Set #cycle = Cast(#depoch / 1029983 as int)
Set #cyear = #depoch%1029983
If #cyear = 1029982
Begin
Set #ycycle = 2820
End
Else
Begin
Set #aux1 = Cast(#cyear / 366 as int)
Set #aux2 = #cyear%366
Set #ycycle = Cast(((2134 * #aux1) + (2816 * #aux2) + 2815) / 1028522 as int) + #aux1 + 1
End
Set #iYear = #ycycle + (2820 * #cycle) + 474
If #iYear <= 0
Begin
Set #iYear = #iYear - 1
End
Set #yday = (#jdn - [dbo].[PersToJul](#iYear, 1, 1)) + 1
If #yday <= 186
Begin
Set #iMonth = CEILING(Convert(Numeric(18,4),#yday) / 31)
End
Else
Begin
Set #iMonth = CEILING((Convert(Numeric(18,4),#yday) - 6) / 30)
End
Set #iDay = (#jdn - [dbo].[PersToJul](#iYear, #iMonth, 1)) + 1
Return Convert(nvarchar(50),#iDay) + '-' + Convert(nvarchar(50),#iMonth) +'-' + Convert(nvarchar(50),#iYear)
End
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
CREATE FUNCTION [dbo].[JulToGre] (#jdn bigint)
Returns nvarchar(11)
AS
Begin
Declare #Jofst as Numeric(18,2)
Set #Jofst=2415020.5
Return Convert(nvarchar(11),Convert(datetime,(#jdn- #Jofst),113),110)
End
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
CREATE FUNCTION [dbo].[COnvertOToN](#StrMyNum NVARCHAR(2))
RETURNS NVARCHAR(2)
AS
BEGIN
DECLARE #MyNunInStr NVARCHAR(10)
SET #MyNunInStr = #StrMyNum
IF LEN(#MyNunInStr) < 2
BEGIN
SET #MyNunInStr = '0' + #MyNunInStr
END
RETURN #MyNunInStr
END
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
-- Changing Date Format
CREATE FUNCTION [dbo].[RevDateShm](#StrDateShamsi NVARCHAR(10), #Seperator CHAR(1))
RETURNS NVARCHAR(10)
AS
BEGIN
DECLARE #StrDayOfMotn NVARCHAR(10)
DECLARE #StrMothOfYear NVARCHAR(10)
DECLARE #StrYearOfYear NVARCHAR(10)
SET #StrDayOfMotn = dbo.COnvertOToN(REPLACE(SUBSTRING(#StrDateShamsi , 1 , ((SELECT CHARINDEX('-' , #StrDateShamsi , 0)))), '-' , ''))
SET #StrMothOfYear = dbo.COnvertOToN(REPLACE(SUBSTRING(#StrDateShamsi , ((CHARINDEX('-' , #StrDateShamsi , 0) )) , 3) , '-' , ''))
SET #StrYearOfYear = RIGHT(#StrDateShamsi , 4)
return (#StrYearOfYear + #Seperator + #StrMothOfYear + #Seperator + #StrDayOfMotn)
END
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
CREATE FUNCTION [dbo].[ConvertShamsiToMiladiDate](#InputShamsiDateString nvarchar(10))
RETURNS datetime
AS
BEGIN
declare #InputShamsiDateString1 nvarchar(10)
declare #yearm int
declare #monthm int
declare #daym int
set #yearm = CONVERT(int , SUBSTRING(#InputShamsiDateString , 1 , 4))
set #monthm = CONVERT(int , SUBSTRING(#InputShamsiDateString , 6 , 2))
set #daym = CONVERT(int , SUBSTRING(#InputShamsiDateString , 9 , 2))
return (select dbo.[JulToGre](dbo.[PersToJul](#yearm,#monthm ,#daym )))
END
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GO
-- The Latest And Main Function
CREATE FUNCTION [dbo].[GetShmsiDate](#InputMiladiDate DateTime , #MySeperatorChar char(1))
RETURNS NVARCHAR(10)
AS
BEGIN
return (select dbo.RevDateShm(dbo.GrToPers(#InputMiladiDate), #MySeperatorChar) AS ShamsiDateOfLog)
END
GO
How to use:
SELECT dbo.GetShmsiDate(GETDATE() , N'/') AS ShamsiDate1,
dbo.GetShmsiDate(GETDATE() , N'-') AS ShamsiDate2
Result:
|ShamsiDate1|ShamsiDate2|
|-----------|-----------|
|1400/11/03 | 1400-11-03|

To convert a date to persian, try this code:
DECLARE #DateString NVARCHAR(200)='2022/09/07';
SELECT FORMAT(CAST(#DateString AS DATE),'yyyy/MM/dd','fa');

Related

Remove duplicate detail transaction (header detail store procedure)

I have problem when creating header detail transaction in store procedure. Assume 1 header contain 3 details transaction. If I want to get invoice I must join some table for getting the formula.
USE [M_TENANT]
GO
/****** Object: StoredProcedure [dbo].[generate_billingv2] Script Date: 07/02/2020 09:32:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[generate_billingv2]
AS
--exec generate_billingv2
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #genbill_nochar INT
,#OPT_UTILITY_NOCHAR NVARCHAR(50)
,#NAME_CHAR VARCHAR(80)
,#opt_utility_detail NVARCHAR(50)
,#MD_BILLING_ID_INT INT
,#BILLING_ID_UTILITY INT
,#OPT_UTILITY_AMT NUMERIC
,#BILLING_ID_FORMULA INT
,#FORMULA_PRICE NUMERIC
,#FORMULA_VA NUMERIC
,#FORMULA_NAME VARCHAR(50)
,#MD_FORMULA_PERCENTAGE DECIMAL(18, 3)
,#bill_TYPE INT
,#BASE_INVOICE_AMT NUMERIC
,#OPT_UTILITY_USED NUMERIC
,#ABODEMEN NUMERIC
,#UNIT_LB DECIMAL(18, 3)
,#TAX_UTILITY NUMERIC(18, 3)
,#TOTAL_UTILITY NUMERIC(18, 3)
,#OPT_GENBILL_NOCHAR VARCHAR(50)
,#NOUNIT_CHAR CHAR(20)
,#OPT_GENBILL_STATUS_INT INT
,#OPT_GENBILL_TRX_DATE DATE
,#OPT_UTILITY_TRX_DATE DATE
,#OPT_TRANS_ID_INT INT
,#OPT_GENERATE_BY VARCHAR(50)
,#MD_FORMULA_PRICE NUMERIC
,#USAGE DECIMAL(18, 2)
,#OPT_FLOOR CHAR(10)
,#MD_FORMULA_NAME VARCHAR(50)
,#OPT_START NUMERIC
,#OPT_BILL_END NUMERIC
,#OPT_START_DATE DATE
,#OPT_END_DATE DATE
,#FORMULA_PERCENTAGE DECIMAL(18, 2)
SET #BASE_INVOICE_AMT = 0
SET #TAX_UTILITY = 0
SET #TOTAL_UTILITY = 0
SET #OPT_GENBILL_STATUS_INT = 0
SET #OPT_GENBILL_TRX_DATE = GETDATE()
SET #OPT_GENERATE_BY = 'AUTO'
DECLARE bill_header CURSOR
FOR
SELECT a.OPT_UTILITY_NOCHAR
,a.NOUNIT_CHAR
,b.UNIT_LB
,b.NAME_CHAR
,b.OPT_FLOOR
,a.OPT_TRANS_ID_INT
,a.OPT_UTILITY_TRX_DATE
,0 AS BASE_INVOICE
,0 AS TAX_UTILITY
,0 AS TOTAL_ULTILITY
FROM OPT_UTILITY a
INNER JOIN OPT_TRANS b ON a.OPT_TRANS_ID_INT = b.OPT_TRANS_ID_INT
WHERE a.OPT_GENBILL_STATUS_INT = 0
OPEN bill_header
FETCH NEXT
FROM bill_header
INTO #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#UNIT_LB
,#NAME_CHAR
,#OPT_FLOOR
,#OPT_TRANS_ID_INT
,#OPT_UTILITY_TRX_DATE
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
WHILE ##FETCH_STATUS = 0
BEGIN
--HEADER TRANSACTION
--PRINT 'ini header'+'-'+ #OPT_UTILITY_NOCHAR
SET #OPT_GENBILL_NOCHAR = convert(VARCHAR, (
SELECT 'KALINV' + convert(VARCHAR(4), YEAR(GETDATE())) + REPLICATE('0', 5 - LEN(RTRIM(invoiced_count))) + RTRIM(invoiced_count)
FROM counter_table
));
INSERT INTO OPT_GENBILL (
OPT_GENBILL_NOCHAR
,OPT_UTILITY_NOCHAR
,NOUNIT_CHAR
,NAME_CHAR
,LB
,BASE_UTILITY
,TAX_UTILITY
,TOTAL_UTILITY
,OPT_GENBILL_STATUS_INT
,OPT_GENBILL_TRX_DATE
,OPT_UTILITY_TRX_DATE
,OPT_TRANS_ID_INT
,OPT_GENERATE_BY
)
VALUES (
#OPT_GENBILL_NOCHAR
,#OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#NAME_CHAR
,#UNIT_LB
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
,#OPT_GENBILL_STATUS_INT
,#OPT_GENBILL_TRX_DATE
,#OPT_UTILITY_TRX_DATE
,#OPT_TRANS_ID_INT
,#OPT_GENERATE_BY
)
DECLARE bill_detail CURSOR
FOR
SELECT C.MD_BILLING_ID_INT AS BILL_TYPE
,a.OPT_UTILITY_NOCHAR
,a.MD_BILLING_ID_INT
,b.MD_FORMULA_PRICE
,b.MD_FORMULA_NAME
,b.MD_FORMULA_PERCENTAGE
,b.MD_FORMULA_PJU_ABD AS ABODEMEN
,b.MD_FORMULA_VA AS FORMULA_VA
,a.OPT_BILL_END - a.OPT_UTILITY_AMT AS OPT_START
,a.OPT_BILL_END
,a.OPT_UTILITY_AMT AS USAGE
,a.OPT_START_DATE
,a.OPT_END_DATE
FROM OPT_UTILITY_DETAIL a
INNER JOIN MD_FORMULA b ON a.MD_BILLING_ID_INT = b.MD_FORMULA_ID_INT
INNER JOIN MD_BILLING_TYPE c ON b.MD_BILLING_ID_INT = c.MD_BILLING_ID_INT
WHERE a.OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
OPEN bill_detail
FETCH NEXT
FROM bill_detail
INTO #BILL_TYPE
,#OPT_UTILITY_NOCHAR
,#MD_BILLING_ID_INT
,#MD_FORMULA_PRICE
,#MD_FORMULA_NAME
,#MD_FORMULA_PERCENTAGE
,#ABODEMEN
,#FORMULA_VA
,#OPT_START
,#OPT_BILL_END
,#USAGE
,#OPT_START_DATE
,#OPT_END_DATE
--IF exists(select TOP 1* from OPT_GENBILL where OPT_UTILITY_NOCHAR=#OPT_UTILITY_NOCHAR)
--BEGIN
-- ROLLBACK TRANSACTION
-- DEALLOCATE bill_detail
-- RAISERROR('invoice sudah pernah generate ',16,-1,#OPT_UTILITY_NOCHAR)
-- RETURN
--END
IF ##FETCH_STATUS <> 0
PRINT ' <<None>>'
WHILE ##FETCH_STATUS = 0
BEGIN
--SET #BASE_INVOICE_AMT = CASE WHEN #BILL_TYPE=3 AND #USAGE<=40 THEN
-- ((#ABODEMEN*(#FORMULA_VA/1000)*#FORMULA_PRICE)+ ((#ABODEMEN*(#FORMULA_VA/1000)*#FORMULA_PRICE)*#FORMULA_PERCENTAGE))
-- when #bill_TYPE=3 and #USAGE>40 then
-- ((#USAGE*(#FORMULA_VA/1000)*#FORMULA_PRICE)+ ((#USAGE*(#FORMULA_VA/1000)*#FORMULA_PRICE)*#FORMULA_PERCENTAGE))
-- when #bill_TYPE=2 then ((#USAGE*#FORMULA_PRICE)+#ABODEMEN)
-- when #bill_TYPE=1 then #UNIT_LB*#FORMULA_PRICE
-- else 0 end
--print #OPT_UTILITY_NOCHAR
-- print #BILL_TYPE
-- print #USAGE
-- print #ABODEMEN
-- print #FORMULA_PRICE
-- print #FORMULA_VA
-- print #FORMULA_PERCENTAGE
INSERT INTO OPT_GENBILL_DETAIL (
OPT_UTILITY_NOCHAR
,NOUNIT_CHAR
,OPT_START_DATE
,OPT_END_DATE
,OPT_BILL_START
,OPT_BILL_END
,OPT_UTILITY_AMT
,OPT_GENBILL_NOCHAR
)
SELECT #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,OPT_START_DATE
,OPT_END_DATE
,OPT_BILL_END - OPT_UTILITY_AMT
,OPT_BILL_END
,CASE
WHEN #BILL_TYPE = 3
AND #USAGE <= 40
THEN ((#ABODEMEN * (#FORMULA_VA / 1000) * #FORMULA_PRICE) + ((#ABODEMEN * (#FORMULA_VA / 1000) * #FORMULA_PRICE) * #FORMULA_PERCENTAGE))
WHEN #bill_TYPE = 3
AND #USAGE > 40
THEN ((#USAGE * (#FORMULA_VA / 1000) * #FORMULA_PRICE) + ((#USAGE * (#FORMULA_VA / 1000) * #FORMULA_PRICE) * #FORMULA_PERCENTAGE))
WHEN #bill_TYPE = 2
THEN ((#USAGE * #FORMULA_PRICE) + #ABODEMEN)
ELSE 0
END
,#OPT_GENBILL_NOCHAR
FROM OPT_UTILITY_DETAIL
WHERE OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
FETCH NEXT
FROM bill_detail
INTO #BILL_TYPE
,#OPT_UTILITY_NOCHAR
,#MD_BILLING_ID_INT
,#MD_FORMULA_PRICE
,#MD_FORMULA_NAME
,#MD_FORMULA_PERCENTAGE
,#ABODEMEN
,#FORMULA_VA
,#OPT_START
,#OPT_BILL_END
,#USAGE
,#OPT_START_DATE
,#OPT_END_DATE
END
CLOSE bill_detail
DEALLOCATE bill_detail
UPDATE counter_table
SET invoiced_count = invoiced_count + 1
UPDATE OPT_UTILITY
SET OPT_GENBILL_STATUS_INT = 1
WHERE OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
-- Get the next vendor.
FETCH NEXT
FROM bill_header
INTO #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#UNIT_LB
,#NAME_CHAR
,#OPT_FLOOR
,#OPT_TRANS_ID_INT
,#OPT_UTILITY_TRX_DATE
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
END
CLOSE bill_header;
DEALLOCATE bill_header;
COMMIT TRANSACTION
RETURN
But the result 3 detail generating 9 details rows.

Unicode (Hexadecimal) to varchar conversion

Here is the problem, the system I use can create a saved search which basically generates a 'Where' clause and saves it in the database as type Image ..
I am trying to convert the image entry to a readable format, it is saved in 2 forms (Unicode and non unicode) now I can get the non unicode entries fine and they display correctly, however when I try and convert the Unicode entries it does not display correctly an example of what I am trying to convert is
0x01000000FFFEFF00FFFEFF0001050000FFFEFF05510075006F007400650006000000060000000100000001000000000000000000000080000000000000FD00000000000000000700000001050000FFFEFF254E006F0072006700720065006E005F00470072006F007500700020004900640020003D00200030007800300030003000300030003000300030003000300030003000300030003200330004000000060000000100000002000000000000000000002380000000000022B00000000000000001000000FFFEFF5454005400490044005F003400330034005200390032003300370020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E004E006F0072006700720065006E005F00470072006F00750070005F004900640020003D00200054005400490044005F00340033003400520039003200330037002E004E006F0072006700720065006E005F00470072006F00750070005F00490064000000000001050000FFFEFF0C45006D0070006C006F0079006500650020003D0020003F0004000000060000000100000002000000000000000000000080000000000001030101000000000001000000FFFEFFA754005400490044005F00320035005200310032003400350034002E0054005400490044005F0032003300520038003600340052003100320034003500340020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E0053006800690070005F0054006F005F0043006F006D00700061006E0079005F004900640020003D00200054005400490044005F00320035005200310032003400350034002E0043006F006D00700061006E0079005F0049006400200041004E004400200054005400490044005F00320035005200310032003400350034002E004100630063006F0075006E0074005F004D0061006E0061006700650072005F004900640020003D00200054005400490044005F003200330052003800360034005200310032003400350034002E0045006D0070006C006F007900650065005F00490064000000000001050000FFFEFF0C45006D0070006C006F0079006500650020003D0020003F0004000000060000000100000002000000000000000000000080000000000001030101000000000001000000FFFEFFB354005400490044005F00320035005200310032003400350034002E0054005400490044005F00320033005200380037003000390052003100320034003500340020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E0053006800690070005F0054006F005F0043006F006D00700061006E0079005F004900640020003D00200054005400490044005F00320035005200310032003400350034002E0043006F006D00700061006E0079005F0049006400200041004E004400200054005400490044005F00320035005200310032003400350034002E0049006E007400650072006E0061006C005F0043006F006D006D00650072006300690061006C005F00530061006C00650073005F004900640020003D00200054005400490044005F0032003300520038003700300039005200310032003400350034002E0045006D0070006C006F007900650065005F00490064000000000001050000FFFEFF13510075006F0074006500200054006F00740061006C0020003E003D00200032003000300030000400000006000000010000000200000000000000000000008000000000001847010101080000000000000000409F400000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D00200054006F00200046006F006C006C006F007700200055007000040000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000200000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D00200049006E00200046006F006C006C006F007700200055007000050000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D0020004E006F00200046006F006C006C006F007700200055007000050000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF20510075006F0074006500200046006F006C006C006F00770020004500780070006900720065007300200049006E002000440061007900730020003E002000310004000000060000000100000002000000000000000000000080000000000039DD0000000000000001000000FFFEFF4854005400490044005F003700310035004C003100340034003600330020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E00510075006F00740065005F005F004900640020003D00200054005400490044005F003700310035004C00310034003400360033002E00510075006F00740065005F005F00490064000000000001050000FFFEFF11510075006F00740065005F0020004900640020004E006F007400200049006E00200004000000060000000100000002000000000000000000000080000000000018F5000000040000000100000000000000000000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000003000000010000000000000000002F9680000000000018F5000000000000000000000000
the SQL code I am using to convert is the following
with saved_lookups_cte as
(select
table_id,
table_name,
saved_lookups_id,
saved_lookup_name,
case
when charindex('WhereDelim',query_text) > 0 then
substring(query_text,len(query_text) - charindex(reverse('WhereDelim'),reverse(query_text)) + 3,4000)
else query_text
end query_text
, sql_tree_binary
from (select
table_id,
table_name,
saved_lookups_id,
saved_lookup_name,
case isUnicode
when 1 then [Production_ED].dbo.[RemoveNonASCII] (cast(cast(substring(sql_tree_binary, startIndex, queryLength * 2) as nvarchar(max))as varchar(max)))
else cast(substring(sql_tree_binary, startIndex, queryLength) as varchar(8000))
end query_text
, sql_tree_binary
from (
select
saved_lookup_name,
case
when substring(sql_tree_binary,1,5) = 0x0100000000 then 0
when substring(sql_tree_binary,1,5) = 0x01000000FF then 1
end isUnicode,
cast(case
when substring(sql_tree_binary,1,5) = 0x0100000000 then
case
when substring(sql_tree_binary,6,1) = 0xFF then substring(sql_tree_binary,8,1) + substring(sql_tree_binary,7,1)
else substring(sql_tree_binary,6,1)
end
when substring(sql_tree_binary,1,5) = 0x01000000FF then
case
when substring(sql_tree_binary,12,1) = 0xFF then substring(sql_tree_binary,14,1) + substring(sql_tree_binary,13,1)
else substring(sql_tree_binary,12,1)
end
end as int) queryLength,
case
when substring(sql_tree_binary,1,5) = 0x0100000000 then
case
when substring(sql_tree_binary,6,1) = 0xFF then 9
else 7
end
when substring(sql_tree_binary,1,5) = 0x01000000FF then
case
when substring(sql_tree_binary,12,1) = 0xFF then 15
else 13
end
end startIndex,
s.table_id,
t.table_name,
s.saved_lookups_id,
s.sql_tree_binary
from
Production_Ed.dbo.Saved_Lookups s inner join
tables t on s.table_id = t.tables_id
-- where substring(saved_lookups_id,1,1) <> 0x00
where saved_lookup_name = 'DE Quotes Open Account Manager >=2000'
) x
) y
)
select * from saved_lookups_cte
The part of the query that does the conversion is
when 1 then [Production_ED].dbo.[RemoveNonASCII]
(cast(cast(substring(sql_tree_binary, startIndex, queryLength * 2) as
nvarchar(max))as varchar(max)))
now this actually returns nothing, however if I set the startIndex to 17 and change the queryLength to 3000 * 2 (unicode byte = 2) I get
??Quote?????Norgren_Group Id = 0x0000000000000023???A??????????????? ????????????? ??????????????????????? ? ??????????????????????????????A?????????? ? ???A??Aa??TTID_25R12454.TTID_23R864R12454 __SQ
Returned, although I can read parts, it is not the full query ... yet even if I extend the length I get no more.
Any help would be greatly appreciated.
Code for the RemoveNonASCII function:
ALTER FUNCTION [dbo].[RemoveNonASCII]
(
#nstring nvarchar(max)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE #Result varchar(max)
SET #Result = ''
DECLARE #nchar nvarchar(1)
DECLARE #position int
SET #position = 1
WHILE #position <= LEN(#nstring)
BEGIN
SET #nchar = SUBSTRING(#nstring, #position, 1)
IF ASCII(#nchar) between 32 and 255
SET #Result = #Result + #nchar
SET #position = #position + 1
END
RETURN #Result
END
GO
Ok, so I found the issue, inside the hex string there were null values, which caused the rest of the returned varchar string to become null .. So I just changed the function to:
AS
BEGIN
DECLARE #Result varchar(max)
SET #Result = ''
DECLARE #nchar nvarchar(1)
DECLARE #position int
SET #position = 1
WHILE #position <= LEN(#nstring)
BEGIN
SET #nchar = SUBSTRING(#nstring, #position, 1)
IF ASCII(#nchar) between 1 and 125
SET #Result = #Result + #nchar
SET #position = #position + 1
END
RETURN #Result
END
Eradicating 0 being the ASCII Null value!

ISDATE Function for different date formats in TSQL

I need to convert VARCHAR values into DATETIME in multiple columns of a view for sorting and formatting (displaying in locale format) purposes in another application on SQL Server 2008.
There are currently two problems.
The input format of the VARCHAR values differ (but consistent at
column level)
Also there may be faulty values (e.g.: 20..05.2015)
Unfortunately the TRY_CONVERT function is available just for SQL Server 2012 and later.
ISDATE does not work because the view contains different date formats and I can neither set the language inside user defined functions nor in views, which would cause ISDATE to work with german date formats for example.
Is there any easier solution for my problem?
My first thought was to write a function like
FUNCTION TryConvertStringAsDatetime ( #value VARCHAR(MAX),
#format INT
)
that uses the format numbers of the CONVERT function, but checking for every possible format manually scares me a bit.
Example: TryConvertStringAsDatetime('20.05.2015', 104) (with some pseudocode)
SET #day = character 1 and 2
SET #month = character 4 and 5
SET #year = character 7, 8, 9 and 10
SET #dateODBCFormat = #year - #month - #day (concatenated with hyphen and not subtracted :)
IF ISDATE(#dateODBCFormat ) = 1
RETURN CONVERT(DATETIME, #dateODBCFormat, 120)
ELSE
RETURN CONVERT(DATETIME, 0) (does the job)
This is the function I now came up with:
CREATE
FUNCTION TryConvertStringAsDatetime ( #value VARCHAR(MAX),
#format INT
)
RETURNS DATETIME
AS
/*
Tries to convert a given VARCHAR value to DATETIME.
Returns NULL if no value was specified or the value is not in the correct format.
*/
BEGIN
DECLARE #length INT = LEN(#value)
IF #length IS NULL OR #length < 10 OR #length > 23
RETURN NULL
DECLARE #day VARCHAR(2),
#month VARCHAR(2),
#year VARCHAR(4),
#time VARCHAR(9)
IF #format = 104 --dd.mm.yyyy hh:mi:ss(24h)
BEGIN
SET #day = SUBSTRING(#value, 1, 2)
SET #month = SUBSTRING(#value, 4, 2)
SET #year = SUBSTRING(#value, 7, 4)
END
ELSE IF #format IN (120, 121) --yyyy-mm-dd hh:mi:ss(24h)
BEGIN
SET #year = SUBSTRING(#value, 1, 4)
SET #month = SUBSTRING(#value, 6, 2)
SET #day = SUBSTRING(#value, 9, 2)
END
ELSE
RETURN NULL -- currently only german and ODBC supported
IF #length > 11
SET #time = SUBSTRING(#value, 12, #length - 11)
SET #value = #year + '-' + #month + '-' + #day + ISNULL(' ' + #time, '')
IF ISDATE(#value) = 1
RETURN CONVERT(DATETIME, #value, 121)
RETURN NULL
END
I would probably go with something like this:
CREATE FUNCTION TryConvertToDate
(
#InputString varchar(20)
)
RETURNS Datetime
BEGIN
DECLARE #DateTime datetime = NULL
SET #DateTime =
CASE
WHEN LEN(#InputString) = 10 AND PATINDEX('[0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]', #InputString)=1 THEN
CONVERT(DateTime, #InputString, 104) -- German
WHEN LEN(#InputString) = 10 AND PATINDEX('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]', #InputString)=1 THEN
CONVERT(DateTime, #InputString, 120) -- ODBC
ELSE
NULL -- unsuported format
END
RETURN #DateTime
END
Note: Testing for length and using patindex ensures only general format, so you need the call this function inside a try block in case the days and months are inverted and will cause a conversion error.
On the other hand, adding supported formats to this function is very easy - all you have to do is add a when clause with the correct patindex and length and the correct convert style.
Another option is to ensure the string can actually be converted to date.
This will make your function more complicated and thus harder to write, but will be easier to work with as it will reduce to minimum the chance of raising a conversion error:
CREATE FUNCTION TryConvertToDate
(
#InputString varchar(20)
)
RETURNS Datetime
BEGIN
DECLARE #DateValue date, #Days int, #Months int, #Years int
IF LEN(#DateString) = 10 AND PATINDEX('[0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]', #InputString)=1 -- German format
BEGIN
SELECT #Days = CAST(LEFT(#InputString, 2) As int),
#Months = CAST(SUBSTRING(#InputString, 4, 2) as int),
#Years = CAST(RIGHT(#InputString, 4) as int)
-- NOTE: you will need to add a condition for leap years
IF (#Days < 31 AND #Months IN(4,6,9,12)) OR (#Days < 30 AND #Months = 2)
SET #DateValue = convert(date, #InputString, 104)
END
IF LEN(#InputString) = 10 AND PATINDEX('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]', #InputString)=1 -- ODBC format
BEGIN
SELECT #Days = CAST(RIGHT(#InputString, 2) As int),
#Months = CAST(SUBSTRING(#InputString, 6, 2) as int),
#Years = CAST(LEFT(#InputString, 4) as int)
-- NOTE: you will need to add a condition for leap years
IF (#Days < 31 AND #Months IN(4,6,9,12)) OR (#Days < 30 AND #Months = 2)
SET #DateValue = convert(date, #InputString, 120)
END
RETURN #DateValue
END
You might have better luck in terms of both speed and functionality doing this in SQLCLR (as noted by #Tab and #Zohar in various comments).
.NET / C# code:
using System;
using System.Data.SqlTypes;
using System.Globalization;
using Microsoft.SqlServer.Server;
public class TryConvertStuff
{
[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlDateTime TryConvertDateTime([SqlFacet(MaxSize = 50)] SqlString
StringDate, [SqlFacet(MaxSize = 10)] SqlString Culture)
{
CultureInfo _Culture = CultureInfo.CurrentCulture;
if (!Culture.IsNull && Culture.Value.Trim() != String.Empty)
{
_Culture = CultureInfo.GetCultureInfo(Culture.Value);
}
DateTime _RealDate;
if (DateTime.TryParse(StringDate.Value, _Culture,
DateTimeStyles.None, out _RealDate))
{
return _RealDate;
};
return SqlDateTime.Null;
}
}
Tests:
SELECT dbo.TryConvertDateTime(N'2019-04-20', N'en'); -- 2019-04-20 00:00:00.000
SELECT dbo.TryConvertDateTime(N'2019-04-20f', N'en'); -- NULL
SELECT dbo.TryConvertDateTime(N'2019.04.20', N'en'); -- 2019-04-20 00:00:00.000
SELECT dbo.TryConvertDateTime(N'20.04.2019', N'en'); -- NULL
SELECT dbo.TryConvertDateTime(N'20.04.2019', N'de'); -- 2019-04-20 00:00:00.000
SELECT dbo.TryConvertDateTime(N'20.04.2019', NULL); -- NULL

Search for a common prefix between two strings

I have a Stored Procedure:
ALTER PROCEDURE [dbo].[traxs_Paybook_Data_Validate]
#session_id varchar(30)
#paybook_start_number varchar(30)
#paybook_end_number varchar(30)
AS
UPDATE traxs_temp..__PaybookImport SET
/* BEGIN CHANGE */
prefix = null,
start_number = CAST(#paybook_start_number AS int),
end_number = CAST(#paybook_end_number AS int)
/* END CHANGE */
WHERE
session_id = #session_id
Values were like:
#paybook_start_number = 100
#paybook_end_number = 200
Now paybook numbers can have a prefix, i.e:
#paybook_start_number = ABC100
#paybook_end_number = ABC200
Prefix is not always the same, neither is its length. I need to find the prefix if one, store it into prefix and remove it from paybook numbers before casting them.
Thanks
Try this:
DECLARE #z VARCHAR(32) = 'ukasd10';
SELECT LEFT(#z, PATINDEX('%[0-9]%', #z) - 1) AS Prefix,REPLACE(SUBSTRING(#z, PATINDEX('%[0-9]%', #z), LEN(#z)), ',', '') AS Digits
and likewise use this logic to update the column Prefix....
Thanks
You need a Function to extract Number/Numeric value from your input string and a function to extract Alphabets from the Input string.
Function To Extract Numbers
CREATE FUNCTION dbo.fn_Extract_Numbers
(
#string NVARCHAR(100)
)
RETURNS INT
AS
BEGIN
DECLARE #int_Value INT;
SELECT #int_Value = LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)
FROM (
SELECT subsrt = SUBSTRING(#string, pos, LEN(#string))
FROM (
SELECT #string AS string , PATINDEX('%[0-9]%', #string) AS Pos
) d
) t
RETURN #int_Value;
END
Function To Extract Alphabets
CREATE FUNCTION dbo.fn_Extract_Alphabets
(
#string NVARCHAR(100)
)
RETURNS NVARCHAR(100)
AS
BEGIN
DECLARE #Alpha_Value NVARCHAR(100);
SELECT #Alpha_Value = LEFT(subsrt, PATINDEX('%[^a-z]%', subsrt + 't') - 1)
FROM (
SELECT subsrt = SUBSTRING(#string, pos, LEN(#string))
FROM (
SELECT #string AS string , PATINDEX('%[a-z]%', #string) AS Pos
) d
) t
RETURN #Alpha_Value;
END
Now use these functions inside your stored procedure to extract the Alphabet/Prefix bit and the Number bit and store them in the target columns.
Something like....
ALTER PROCEDURE [dbo].[traxs_Paybook_Data_Validate]
#session_id varchar(30)
#paybook_start_number varchar(30)
#paybook_end_number varchar(30)
AS
DECLARE #Start_Num_Prefix VARCHAR(100);
DECLARE #End_Num_Prefix VARCHAR(100);
DECLARE #Start_Num_Numbers INT;
DECLARE #End_Num_Numbers INT;
SELECT #Start_Num_Prefix = dbo.fn_Extract_Alphabets(#paybook_start_number)
SELECT #End_Num_Prefix = dbo.fn_Extract_Alphabets(#paybook_end_number)
SELECT #Start_Num_Numbers = dbo.fn_Extract_Numbers(#paybook_start_number)
SELECT #End_Num_Numbers = dbo.fn_Extract_Numbers(#paybook_end_number)
..... rest of your procedure and so on....

Selecting First String from Record SQL

I have a query which so far returns the following;
Stock Code BomReference Description
2134601A 5134601A ***DISC*** 004601 EXP Pack I PC Spoo (NF) 500MLX6
2134601A 5109052 40010934 IPC2101 UK PACK PC SHAMPOO (NF) 500MLX6
2134601A 5134601B 40010908 004601 EXP PACK PC SHAMPOO 500MLX6
2134601A 5109052L 40010909 IPC2101L UK PACK IPC SPOO 500ML X 6
The code is as follows;
SELECT BomComponents.StockCode, BomHeaders.BomReference, BomHeaders.Description
FROM BomComponents INNER JOIN
BomHeaders ON BomComponents.HeaderID = BomHeaders.ID
WHERE StockCode = '2134601A'
I want to be able to select just the first word/number from Description and then group the bom reference and Description together to result in the following.
StockCode BomReference Description
2134601A 5134601A, 5109052, 5134601B, 5109052L ***DISC***, 40010934, 40010908, 40010909
Any help would be massively helpful.
Creating the function below should accomplish this for you. I use it VERY frequently.
select dbo.getTokenValue([Your String], [Delimiting Character], [Position])
In this case:
select dbo.getTokenValue(Description, ' ', 1)
/****** Object: UserDefinedFunction [dbo].[getTokenValue] Script Date: 7/8/2014 1:08:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
Accepts the string, delimeter and the position of the required value and returns the value
*/
create function [dbo].[getTokenValue] (#tokenvalue varchar(200), #Delimeter char, #pos int)
returns varchar(200)
Begin
Declare #DelimPos int
Declare #remSubstr varchar(200)
Declare #FinalStr varchar(200)
Declare #Count int
Declare #Countdelim int
set #Finalstr = ''
Set #Countdelim = 0
Set #remSubstr = #tokenValue
Set #Count = #pos-1
set #countdelim = 1
while #Count <> 0
Begin
Set #DelimPos = charindex(#Delimeter,#remSubstr)
If #DelimPos = 0
Break;
set #remSubstr = substring(#remSubstr,#DelimPos+1,Len(#remSubstr)-#DelimPos)
set #Count = #Count -1
set #CountDelim = #CountDelim + 1
End
If #Pos > #CountDelim
Begin
set #Finalstr = null
return #FinalStr
end
else
Begin
Set #DelimPos = charindex(#Delimeter,#remSubstr)
if #DelimPos = 0
Set #Finalstr = #remsubstr
else
Set #FinalStr = substring(#remSubstr,1,#DelimPos-1)
end
return #FinalStr
end
GO

Resources