Change SQL Server date string ot other format - sql-server

Please forgive me for my dunglish, I am dutch.
I have a table that looks like this:
CREATE TABLE [dbo].[WSLogons]
(
[Date] [nchar](15) NULL,
[Time] [nchar](15) NULL,
[Username] [nchar](15) NULL,
[Domain] [nchar](15) NULL,
[Computer] [nchar](15) NULL,
[HostComputerName] [nchar](15) NULL
) ON [PRIMARY]
There is no primary key.
I fill this table with some user data and I made a big mistake well multiple but I am facing the fact that my date and time columns are filled wrong.
This is have solved but in my database I have different date and time formats.
and I am querying with a convert date and time function.
This is not working because in some rows, I have date and time values like this:
5/18/2018 9:00 AM
5/18/2018 8:28 AM
and in some in the right way like this
18-05-2018 14:52
as I was saying, I query for information with a order by and a convert
order by CONVERT(date, Date, 105) desc
If in the results are date and time with the US notation, I get a format error.
Now I am as you can see not a SQL guru. I have corrected the script that is filling the table but now I want to convert the wrong dates into the right format so the data is saved.
I'd like to get a nice result in a query with this statement.
SELECT
CONVERT(date, [Date] ,101) as datum
,[Time]
,[Username]
,[Domain]
,[Computer]
,[HostComputerName]
FROM
[AuditLogons].[dbo].[WSLogons]
WHERE
date LIKE '%/%/%'
AND Time LIKE '%:% AM%' OR Time LIKE '%:% PM%'
Now the datum column is presented as
2018-05-18 11:59 AM
2018-05-18 1:25 PM
How do I get from here to update those rows in formatting the date like 18-5-2018?
If I try to convert to do
CONVERT(date, [Date], 105)
I get an error, too.
Hope you can understand my problem and I hope for some help
Many thanks.
Roger

This seems to work, but the underlying issue is that rule number one of database design is to use the appropriate data types. If you can change those columns, do it; if you can't, make sure you are validating your input.
DECLARE #WSLogons TABLE(
[Date] [nchar](15) NULL,
[Time] [nchar](15) NULL
)
INSERT INTO #WSLogons ([Date],[Time]) SELECT '5/18/2018','9:00 AM'
INSERT INTO #WSLogons ([Date],[Time]) SELECT '5/18/2018','09:00'
SELECT *
,CONVERT(datetime2, [Date] + ' ' + [Time]) as datum
FROM #WSLogons

first add real date column to your table:
alter table dbo.WSLogons add realDate datetime;
then update it with proper data ie:
update dbo.WSLogons
set realDate = CONVERT(datetime, Date, 101)
where Date like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]'
for date format in dd/mm/yyyy style
for other formats see here

Related

convert different string date formats from single column to one form of output in sql server

I have one date columns as varchar datatype which has multiple date formats. I have to convert all different formats into one date format as 'YYYY-MM-DD'.
I am trying to convert it but couldn't make it. Below are different formats available in column.
Input
8/15/2022
15-Aug-22
15/08/2022
Required Output
2022-08-15
Honestly, I think you need to take the pessimistic approach here and assume that, possibly for a lot of your data, you don't know what the value is meant to be. As I stated in the comments, if you have the value '01/12/2021' is that 1 December 2021 or 12 January 2021, how do you know, and more importantly how would SQL Server know? As such, for dates like this you don't know and therefore the value NULL is more appropriate that a guess.
Here I use 3 different formats, an implicit one, and then 2 explicit ones (MM/dd/yyyy and dd/MM/yyyy) Then I check if the MIN and MAX values match (NULL values are ignored for aggregation), and if they do return that value. If they don't then NULL, as what value the date is is ambiguous and therefore intentionally shown as an unknown value (NULL):
You can, if needed, add more styles to the below, but this should be enough for you to work with.
CREATE TABLE dbo.YourTable (ID int IDENTITY(1,1), --I assume you have a unique identifier
StringDate varchar(20));
INSERT INTO dbo.YourTable (StringDate)
VALUES('8/15/2022'), --Must be M/d/yyyy
('15-Aug-22'),
('15/08/2022'), --Must be dd/MM/yyyy
('12/01/2021'); --Could be MM/dd/yyyy or dd/MM/yyyy
GO
SELECT YT.ID,
YT.StringDate,
CASE MAX(V.SomeDate) WHEN MIN(V.SomeDate) THEN MAX(V.SomeDate) END AS DateDate
FROM dbo.YourTable YT
CROSS APPLY (VALUES(TRY_CONVERT(date,YT.StringDate)), --Implicit conversion
(TRY_CONVERT(date,YT.StringDate,101)), --US style MM/dd/yyyy
(TRY_CONVERT(date,YT.StringDate,103)))V(SomeDate) --UK style dd/MM/yyyy
GROUP BY YT.ID,
YT.StringDate;
GO
DROP TABLE dbo.YourTable;
db<>fiddle
You can use a combination of TRY_CONVERT and REPLACE function in a CASE operator to do so.
As an example :
DECLARE #T TABLE(STR_DATE VARCHAR(32));
INSERT INTO #T VALUES
('8/15/2022'),
('15-Aug-22'),
('15/08/2022');
SELECT CASE
WHEN TRY_CONVERT(DATE, STR_DATE, 101) IS NOT NULL
THEN CONVERT(DATE, STR_DATE, 101)
WHEN TRY_CONVERT(DATE, REPLACE(STR_DATE, '-', ' '), 6) IS NOT NULL
THEN CONVERT(DATE, REPLACE(STR_DATE, '-', ' '), 6)
WHEN TRY_CONVERT(DATE, STR_DATE, 103) IS NOT NULL
THEN CONVERT(DATE, STR_DATE, 103)
END
FROM #T

SQL Server: combine date column and time column, insert into datetime column

I have a database with a date and a time stored separately in datetime columns (not my idea). I need to combine their values to put into another table with a datetime column. As simple as this seems, I just don't seem to be able to do it.
I can get my date value:
cast(sampledate as date) -- returns '2014-11-01'
And my date value:
cast(CollectionTime as time) -- returns '06:46:00.0000000'
I've tried a few different ways of putting them together that look OK.
For example:
concat(cast(sampledate as date) , ' ' , cast(CollectionTime as time)) -- returns '2014-11-05 08:14:00.0000000'
But when I try to insert this into a datetime column, or even just cast it as a datetime value, it doesn't work:
cast(concat(cast(sampledate as date) , ' ' , cast(CollectionTime as time)) as datetime)
-- I get the error 'Conversion failed when converting date and/or time from character string.'
This link warned me against using the FORMAT function, and I've been to some other sites that tell me what NOT to do, but I just can't seem to do this simple thing. Can anyone help? Thanks.
EDIT: Figured it out. This link solved it for older versions of SQL, but not current versions. However, it works fine if you cast to datetime2(0), not datetime.
As I commented above, here is an example where you can add the two datetimes together.
If either column is NOT datetime, simply convert that column to a datetime
Declare #YourTable table (sampledate datetime,CollectionTime datetime)
Insert Into #YourTable values
('2019-06-25 00:00:00','09:09:31')
Select *
,NewDateTime = sampleDate + CollectionTime
From #YourTable
Results
sampledate CollectionTime NewDateTime
2019-06-25 00:00:00.000 1900-01-01 09:09:31.000 2019-06-25 09:09:31.000

How would one create a DATE column that is updated via a DATETIME column

Consider the following:
CREATE TABLE mytable
(
[id] INT NOT NULL,
[foobar] VARCHAR(25) NULL,
[created_on] DATETIME NOT NULL
);
SELECT *
FROM mytable
WHERE CAST(created_on AS DATE) = '2019-01-01';
I have a lot of queries like this, where I need to store the full date and time for audit (and sorting) purposes, but most queries only care about the date portion when it comes to searching.
In order to improve performance, I was considering adding a sister column that stores the value as a DATE, and then update it via triggers; but before I go down that rabbit hole, I wanted to know if there is a better way to solve this issue. Is there some mechanism in SQL Server that offers a better solution to this issue?
I am currently stuck on SQL Server 2008, but I am open to solutions that use newer versions
My preference would be to just write a sargable
WHERE created_on >= '2019-01-01' and created_on < '2019-01-02';
The
CAST(created_on AS DATE) = '2019-01-01';
Is in fact mostly sargable but somewhat sub optimal ...
... and splitting it out into a separate indexed column can help other cases like GROUP BY date
If you decide you do need a separate column you can create a computed column and index that.
This is preferable to triggers as it has less performance overhead as well as allowing SQL Server to match both the column name and the original expression. (any index on a column populated by a trigger won't be matched to a query containing CAST(created_on AS DATE))
CREATE TABLE mytable
(
[id] INT NOT NULL,
[foobar] VARCHAR(25) NULL,
[created_on] DATETIME NOT NULL,
[created_on_date] AS CAST(created_on AS DATE)
);
CREATE INDEX ix_created_on_date
ON mytable(created_on_date)
include (foobar, id, created_on)
SELECT foobar,
id,
created_on
FROM mytable
WHERE CAST(created_on AS DATE) = '2019-01-01';

How to save Hijri dates in sql server tables? What type of column?

How to save Hijri dates (0000/01/01-9999/01/01) in Microsoft SQL Server tables? What type of column?
I choose datetime2, is it right?
CREATE TABLE [dbo].[MyDates](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Title] [nvarchar](50) NULL,
[Date] [datetime2](0) NULL,
CONSTRAINT [PK_MyDates] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
I dont know why people downvote this but if you have ever written a program that interacts with Persian dates and you need to generate reports based on dates and times you will understand why you should store it as pure string value. sql server lacks the ability to convert UTC to different time zones and you should use clr to do that and many hosting environment does not allow you to do that
I recommend you to store them in fixed format like yyyy/MM/dd HH:mm:ss in char(19) column if you ever want to have reports based on Hijri date, also store the UTC time in another column for further uses or globalization.
If you store them with the pattern I mentioned above you can compare them easily and also get specific part of the date time (year, hour, ...) just by extracting part of the value by using SUBSTRING
Keep in mind that you can always store the UTC time with time zone in your database but my experience shows that you will have difficulties with reports soon or later.
Another point is that never try to store Hijri dates in DateTimes because you can not do that. for example 1394/02/31 is a Hijri date but you can not have 31st day of February in DateTime.
Assume you want to generate report of items that are created in each day. if you store the date just as UTC you must to convert each date time to Hijri by specific time zone difference and daylight time saving and then group by it and you will face huge performance degradation. For example try to calculate the report for 1393/12/20 to 1394/01/10 and then you will understand why not use UTC date times for this kind of reporting stuffs.
Store them in datetime2 -- they should go in as utc dates. If you have strings, convert them using CONVERT passing the style code 131.
DECLARE #HijriDateString VARCHAR(10) = '02/02/1435';
declare #HijriDate datetime2 = CONVERT(DATETIME, #HijriDateString, 131);
declare #FormattedOuput varchar(255) = convert(nvarchar(255), #HijriDate, 131);
select #HijriDateString as [original string], #HijriDate as [parsed datetime2], #FormattedOuput as [formatted output]
-- original string parsed datetime2 formatted output
-- 02/02/1435 2013-12-05 00:00:00.0000000 2/02/1435 12:00:00.0000000AM
Then when you present the date to the user, you format it back out as Hijri.
By keeping it in datetime2, you can do proper date arithmetic, using things like
MyDateColumn < getutcdate()
To do correct comparisons.
EDIT for #Dotctor's question Does a normal grouping by day not work? There's every chance I'm missing something key, so I'd be glad to learn
begin tran
create table #hijriDateExample (id int, d datetime2)
insert into #hijriDateExample values
(1, CONVERT(DATETIME, '02/02/1435 01:00' , 131)),
(2, CONVERT(DATETIME, '02/02/1435 22:00' , 131)),
(3, CONVERT(DATETIME, '03/02/1435 04:00' , 131))
select dateadd(DAY,0, datediff(day,0, d)), count(*) as [numberOfDays] from #hijriDateExample
group by dateadd(DAY,0, datediff(day,0, d))
-- 2013-12-05 00:00:00.000 2
-- 2013-12-06 00:00:00.000 1
rollback tran
You can use column of type (Hijri_Date varchar(10))
and it will be easy to save and easy to make reports and query between 2 dates.
In C# asp.net use the following steps:
1- Add script manager to your web-form. and set the property EnableScriptGlobalization = true , EnableScriptLocalization = true
2- Add HijriDate text box.
3- Add Button to select Hijri Date.
4- Add CalendarExtender from Ajaxtoolbox and add the following properties for example
PopupButtonID="btnDate" TargetControlID="txtapptdate".
5- Change the format property for CalendarExtender to dd/MM/yyyy.
6- change the property for text-box read only = true.
7- Add the following culture values to your header page in html to convert calender from Gregorian date to Hijri date :
UICulture="ar" Culture="ar-SA".
8- When you save and insert to SQL server the date you can use the value as usual Hijri_Date.Text
9- to compare later and make filter and search screen or reports and if you need to find out the records between 2 dates use the format function to change the DATE output format and convert function to convert varchar to date in select statement like this:
select format(cast(Hijri_date as date),'dd/MM/yyyy','ar-sa')
from Table1
where Hijri_date between '10/05/1439' and '20/10/1439'
This help me a lot.
Declare #Hdate nvarchar(50)
set #Hdate = convert(varchar(10),convert(date,convert(varchar(12),getdate(),131),103),112)
It is not possible to use DateTime field due to the Feb issue.
Hence solution is to use a NVARCHAR field an save in it and then later convert to date.

Getting all rows created today

I am unable to get all the rows created today. I have used multiple functions like getdate(), Cast, Convert, etc. but all in vain.
This is my basic query:
SELECT timeId
FROM table_roaster_time_table
WHERE (user_id = #user_id) AND (DATEDIFF(d, date, GETDATE()) = 0)
I want to get the timeId from the table table_roaster_time_table where userid will be provided and the date is today.
How do I do this?
In order to keep any chance of using an index on the [date] column (even if one doesn't exist today, it may in the future), try:
AND [date] >= DATEADD(DAY, 0, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP))
AND [date] < DATEADD(DAY, 1, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP));
If you're using SQL Server 2008 or better, you can do something like this to shorten the code but still make use of an index on [date] if one exists:
AND CONVERT(DATE, [date]) = CONVERT(DATE, CURRENT_TIMESTAMP);
EDIT
Since you seem to be confused why 3/6/2012 is March 6th and not June 3rd, I might also suggest that instead of manually inserting ambiguous date literals like '3/6/2012' into the database, you make the column a default such as:
ALTER TABLE dbo.table_roaster_time_table
ALTER COLUMN [date] DATETIME NOT NULL;
ALTER TABLE dbo.table_roaster_time_table
ADD CONSTRAINT df_date DEFAULT (CURRENT_TIMESTAMP)
FOR [date];
If you're going to insert date literals then at least use a safe and unambiguous format, such as YYYYMMDD:
INSERT dbo.table_roaster_time_table([date]) VALUES('20120603');
Now there is no confusion.

Resources