Unicode (Hexadecimal) to varchar conversion - sql-server

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!

Related

Extract and Separate Numeric

I have a table below.
Client Name
-----------------------
Mukherjee_ 2697231 Gehrmann _ 298053524
Butt Glen_740708968 Amanda_259055000
Quirk Michael_ 65941412 and Leanne _817498908
Butt Glen_740708968 Amanda_259055000 Tristan 3939393939
Kryger Aaron _ 606506375
Krebs Paul
Haddrill Clare _ 333900499 McRedmond Patrick _557887778
I need to extract the numbers only and the numbers must be separated.
Numeric
----------------
2697231 298053524
740708968 259055000
65941412 817498908
740708968 259055000 3939393939
606506375
333900499 557887778
I have used the function below, however it concatenates all the numbers together.
ALTER FUNCTION [dbo].[UDF_GetNumeric]
(#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
I'm using SQL Server 2012.
Upon looking further into this problem, I came up with -->
-- partition into non-num and numeric strings, collapse non-num into single space, and copy numeric as is
-- complicating: multiple non-num and multiple numeric strings
-- further, allow for starting with EITHER non-num or numeric
-- further, can have no numeric at all, or can have no non-num at all
I put data into table dbo.separatenumber
And created UDF--> Revised Jan 15th--del If/Then/Set #next, add Set #LeftMost
/****** Object: UserDefinedFunction [dbo].[fnSeparateNonNumericCharacters] Script Date: 01/14/2020 21:41:42 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fnSeparateNonNumericCharacters]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fnSeparateNonNumericCharacters]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE Function [dbo].[fnSeparateNonNumericCharacters](#strText VARCHAR(1000)) RETURNS VARCHAR(1000) AS
BEGIN
Declare #outText as varchar(1000), #LeftMost as char(4), #ndx as int
Set #outText = ''
IF PATINDEX('[0-9]', SUBSTRING(#strText,1,1)) = 1 -- is the 1st char numeric?
Set #LeftMost = 'Nums'
ELSE
Set #LeftMost = 'Text'
;
WHILE LEN(#strText) > 0
BEGIN
IF #LeftMost = 'Text'
BEGIN
Set #ndx = PATINDEX('%[0-9]%', #strText) -- where is the next Numeric
If #ndx = 0 Break -- bail when no more
Set #strText = SUBSTRING(#strText, #ndx, LEN(#strText) - #ndx + 1) -- bypass Text
Set #LeftMost = 'Nums'
END
ELSE -- #LeftMost = 'Nums'
BEGIN
Set #ndx = PATINDEX('%[^0-9]%', #strText) -- where is next Text
If #ndx = 0 Set #ndx = LEN(#strText) + 1 -- use EOL plus one when no more
Set #outText += SUBSTRING(#strText, 1, #ndx - 1) + ' ' -- Grab Numbers plus a space
If #ndx = LEN(#strText) + 1 Break -- bail when no more
Set #strText = SUBSTRING(#strText, #ndx, LEN(#strText) - #ndx + 1 ) -- move past this Num
Set #LeftMost = 'Text'
END
;
END
RETURN #outText -- here it is
END
GO
select
*
, dbo.fnSeparateNonNumericCharacters(clientname) as Numbers
from dbo.separatenumber
Sample output
ClientID ClientName Numbers
11 Mukherjee_ 2697231 Gehrmann _ 298053524 2697231 298053524
22 Butt Glen_740708968 Amanda_259055000 740708968 259055000
33 Quirk Michael_ 65941412 and Leanne _817498908 65941412 817498908
44 Butt Glen_740708968 Amanda_259055000 Tristan 3939393939 740708968 259055000 3939393939
55 Kryger Aaron _ 606506375 606506375
66 Krebs Paul
77 Haddrill Clare _ 333900499 McRedmond Patrick _557887778 333900499 557887778

How to split a dynamic string in rows (right to Left)

This query converts dynamic int to binary, but I want to split into rows.
declare #value int
set #value = 96
declare #result varchar(32)
set #result = ''
while 1 = 1
begin
select
#result = convert(char(1), #value % 2) + ',' +#result,
#value = convert(int, #value / 2)
if #value = 0 break
end
select substring(#result, 1, len(#result)-1) as result
Please help me to find a solution.
This is the result of my query.
1,1,0,0,0,0,0
My question is: how can I split this result into rows from right to left?
My result will need to be this (I'm trying to insert into a #table):
0
0
0
0
0
1
1
Thanks
Using a WHILE seems like a really bad idea. If you want to achieve what you have this would be a far faster solution:
DECLARE #I int = 96
SELECT CONVERT(bit,#i & V.b)
FROM (VALUES(1),(2),(4),(8),(16),(32),(64)) V(b)
ORDER BY V.b;

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

T-SQL: How can I compare two variables of type XML when length > VarChar(MAX)?

Using only SQL Server 2008 R2 (this is going to be in a stored proc), how can I determine if two variables of type XML are equivalent?
Here is what I want to do:
DECLARE #XmlA XML
DECLARE #XmlB XML
SET #XmlA = '[Really long Xml value]'
SET #XmlB = '[Really long Xml value]'
IF #XmlA = #XmlB
SELECT 'Matching Xml!'
But as you probably know, it returns:
Msg 305, Level 16, State 1, Line 7 The XML data type cannot be
compared or sorted, except when using the IS NULL operator.
I can convert to VarChar(MAX) and compare, but that only compares the first 2MB. Is there another way?
Check this SQL function:
CREATE FUNCTION [dbo].[CompareXml]
(
#xml1 XML,
#xml2 XML
)
RETURNS INT
AS
BEGIN
DECLARE #ret INT
SELECT #ret = 0
-- -------------------------------------------------------------
-- If one of the arguments is NULL then we assume that they are
-- not equal.
-- -------------------------------------------------------------
IF #xml1 IS NULL OR #xml2 IS NULL
BEGIN
RETURN 1
END
-- -------------------------------------------------------------
-- Match the name of the elements
-- -------------------------------------------------------------
IF (SELECT #xml1.value('(local-name((/*)[1]))','VARCHAR(MAX)'))
<>
(SELECT #xml2.value('(local-name((/*)[1]))','VARCHAR(MAX)'))
BEGIN
RETURN 1
END
---------------------------------------------------------------
--Match the value of the elements
---------------------------------------------------------------
IF((#xml1.query('count(/*)').value('.','INT') = 1) AND (#xml2.query('count(/*)').value('.','INT') = 1))
BEGIN
DECLARE #elValue1 VARCHAR(MAX), #elValue2 VARCHAR(MAX)
SELECT
#elValue1 = #xml1.value('((/*)[1])','VARCHAR(MAX)'),
#elValue2 = #xml2.value('((/*)[1])','VARCHAR(MAX)')
IF #elValue1 <> #elValue2
BEGIN
RETURN 1
END
END
-- -------------------------------------------------------------
-- Match the number of attributes
-- -------------------------------------------------------------
DECLARE #attCnt1 INT, #attCnt2 INT
SELECT
#attCnt1 = #xml1.query('count(/*/#*)').value('.','INT'),
#attCnt2 = #xml2.query('count(/*/#*)').value('.','INT')
IF #attCnt1 <> #attCnt2 BEGIN
RETURN 1
END
-- -------------------------------------------------------------
-- Match the attributes of attributes
-- Here we need to run a loop over each attribute in the
-- first XML element and see if the same attribut exists
-- in the second element. If the attribute exists, we
-- need to check if the value is the same.
-- -------------------------------------------------------------
DECLARE #cnt INT, #cnt2 INT
DECLARE #attName VARCHAR(MAX)
DECLARE #attValue VARCHAR(MAX)
SELECT #cnt = 1
WHILE #cnt <= #attCnt1
BEGIN
SELECT #attName = NULL, #attValue = NULL
SELECT
#attName = #xml1.value(
'local-name((/*/#*[sql:variable("#cnt")])[1])',
'varchar(MAX)'),
#attValue = #xml1.value(
'(/*/#*[sql:variable("#cnt")])[1]',
'varchar(MAX)')
-- check if the attribute exists in the other XML document
IF #xml2.exist(
'(/*/#*[local-name()=sql:variable("#attName")])[1]'
) = 0
BEGIN
RETURN 1
END
IF #xml2.value(
'(/*/#*[local-name()=sql:variable("#attName")])[1]',
'varchar(MAX)')
<>
#attValue
BEGIN
RETURN 1
END
SELECT #cnt = #cnt + 1
END
-- -------------------------------------------------------------
-- Match the number of child elements
-- -------------------------------------------------------------
DECLARE #elCnt1 INT, #elCnt2 INT
SELECT
#elCnt1 = #xml1.query('count(/*/*)').value('.','INT'),
#elCnt2 = #xml2.query('count(/*/*)').value('.','INT')
IF #elCnt1 <> #elCnt2
BEGIN
RETURN 1
END
-- -------------------------------------------------------------
-- Start recursion for each child element
-- -------------------------------------------------------------
SELECT #cnt = 1
SELECT #cnt2 = 1
DECLARE #x1 XML, #x2 XML
DECLARE #noMatch INT
WHILE #cnt <= #elCnt1
BEGIN
SELECT #x1 = #xml1.query('/*/*[sql:variable("#cnt")]')
--RETURN CONVERT(VARCHAR(MAX),#x1)
WHILE #cnt2 <= #elCnt2
BEGIN
SELECT #x2 = #xml2.query('/*/*[sql:variable("#cnt2")]')
SELECT #noMatch = dbo.CompareXml( #x1, #x2 )
IF #noMatch = 0 BREAK
SELECT #cnt2 = #cnt2 + 1
END
SELECT #cnt2 = 1
IF #noMatch = 1
BEGIN
RETURN 1
END
SELECT #cnt = #cnt + 1
END
RETURN #ret
END
Here is the Source
The function fails to compare XML fragments e.g. when there is not a single root element, like:
SELECT dbo.CompareXml('<data/>', '<data/><data234/>')
In order to fix this, you must wrap your XMLs in root elements, when they are passed to the function or edit the function to do this. For, example:
SELECT dbo.CompareXml('<r><data/></r>', '<r><data/><data234/></r>')
There are many different ways of comparing two XML documents, and a lot depends on what kind of differences you want to tolerate: you definitely need to tolerate differences in encoding, attribute order, insignificant whitespace, numeric character references, and use of attribute delimiters, and you should probably also tolerate differences in use of comments, namespace prefixes, and CDATA. So comparing two XML documents as strings is definitely not a good idea - unless you invoke XML canonicalization first.
For many purposes the XQuery deep-equals() function does the right thing (and is more-or-less equivalent to comparing the canonical forms of the two XML documents). I don't know enough about Microsoft's SQL Server implementation of XQuery to tell you how to invoke this from the SQL level.
You may cast fields to varbinary(max), hash them and compare hashes. But you definitely miss if XMLs are equivalent but not identical
To calculate hash you may use either CLR function:
using System;
using System.Data.SqlTypes;
using System.IO;
namespace ClrHelpers
{
public partial class UserDefinedFunctions {
[Microsoft.SqlServer.Server.SqlFunction]
public static Guid HashMD5(SqlBytes data) {
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
md5.Initialize();
int len = 0;
byte[] b = new byte[8192];
Stream s = data.Stream;
do {
len = s.Read(b, 0, 8192);
md5.TransformBlock(b, 0, len, b, 0);
} while(len > 0);
md5.TransformFinalBlock(b, 0, 0);
Guid g = new Guid(md5.Hash);
return g;
}
};
}
Or sql function:
CREATE FUNCTION dbo.GetMyLongHash(#data VARBINARY(MAX))
RETURNS VARBINARY(MAX)
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE #res VARBINARY(MAX) = 0x
DECLARE #position INT = 1, #len INT = DATALENGTH(#data)
WHILE 1 = 1
BEGIN
SET #res = #res + HASHBYTES('MD5', SUBSTRING(#data, #position, 8000))
SET #position = #position+8000
IF #Position > #len
BREAK
END
WHILE DATALENGTH(#res) > 16 SET #res= dbo.GetMyLongHash(#res)
RETURN #res
END
If you can use SQL CLR, I suggest to write a function using XNode.DeepEquals Method:
var xmlTree1 = new XElement("Root",
new XAttribute("Att1", 1),
new XAttribute("Att2", 2),
new XElement("Child1", 1),
new XElement("Child2", "some content")
);
var xmlTree2 = new XElement("Root",
new XAttribute("Att1", 1),
new XAttribute("Att2", 2),
new XElement("Child1", 1),
new XElement("Child2", "some content")
);
Console.WriteLine(XNode.DeepEquals(xmlTree1, xmlTree2));
If you cannot, you can write your own function (see SQL FIDDLE EXAMPLE):
CREATE function [dbo].[udf_XML_Is_Equal]
(
#Data1 xml,
#Data2 xml
)
returns bit
as
begin
declare
#i bigint, #cnt1 bigint, #cnt2 bigint,
#Sub_Data1 xml, #Sub_Data2 xml,
#Name varchar(max), #Value1 nvarchar(max), #Value2 nvarchar(max)
if #Data1 is null or #Data2 is null
return 1
--=========================================================================================================
-- If more than one root - recurse for each element
--=========================================================================================================
select
#cnt1 = #Data1.query('count(/*)').value('.','int'),
#cnt2 = #Data1.query('count(/*)').value('.','int')
if #cnt1 <> #cnt2
return 0
if #cnt1 > 1
begin
select #i = 1
while #i <= #cnt1
begin
select
#Sub_Data1 = #Data1.query('/*[sql:variable("#i")]'),
#Sub_Data2 = #Data2.query('/*[sql:variable("#i")]')
if dbo.udf_XML_Is_Equal_New(#Sub_Data1, #Sub_Data2) = 0
return 0
select #i = #i + 1
end
return 1
end
--=========================================================================================================
-- Comparing root data
--=========================================================================================================
if #Data1.value('local-name(/*[1])','nvarchar(max)') <> #Data2.value('local-name(/*[1])','nvarchar(max)')
return 0
if #Data1.value('/*[1]', 'nvarchar(max)') <> #Data2.value('/*[1]', 'nvarchar(max)')
return 0
--=========================================================================================================
-- Comparing attributes
--=========================================================================================================
select
#cnt1 = #Data1.query('count(/*[1]/#*)').value('.','int'),
#cnt2 = #Data1.query('count(/*[1]/#*)').value('.','int')
if #cnt1 <> #cnt2
return 0
if exists (
select *
from
(
select
T.C.value('local-name(.)', 'nvarchar(max)') as Name,
T.C.value('.', 'nvarchar(max)') as Value
from #Data1.nodes('/*[1]/#*') as T(C)
) as D1
full outer join
(
select
T.C.value('local-name(.)', 'nvarchar(max)') as Name,
T.C.value('.', 'nvarchar(max)') as Value
from #Data2.nodes('/*[1]/#*') as T(C)
) as D2
on D1.Name = D2.Name
where
not
(
D1.Value is null and D2.Value is null or
D1.Value is not null and D2.Value is not null and D1.Value = D2.Value
)
)
return 0
--=========================================================================================================
-- Recursively running for each child
--=========================================================================================================
select
#cnt1 = #Data1.query('count(/*[1]/*)').value('.','int'),
#cnt2 = #Data2.query('count(/*[1]/*)').value('.','int')
if #cnt1 <> #cnt2
return 0
select #i = 1
while #i <= #cnt1
begin
select
#Sub_Data1 = #Data1.query('/*/*[sql:variable("#i")]'),
#Sub_Data2 = #Data2.query('/*/*[sql:variable("#i")]')
if dbo.udf_XML_Is_Equal(#Sub_Data1, #Sub_Data2) = 0
return 0
select #i = #i + 1
end
return 1
END
I stumbled upon this fairly comprehensive article which goes into more detail of actually comparing the CONTENT of 2 XML entries to determine whether they are the same. It makes sense, as the ordering of attributes in nodes CAN differ, even though their values are exactly the same. I'd recommend you read through it and even implement the function to see if it works for you... I tried it out quickly and it seemed to work for me?

How to convert datetime in Persian in 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');

Resources