Reputation: 6400
We have a really stupid data requirement for dates in our database. The month, day, year, minute, & hour are stored in separate columns. Obviously, this is not ideal for querying date ranges especially using Entity Framework.
We decided to just create a new column called combinedDate
that is a SQL smalldatetime
with the correlating date info. While trying to update our db, our application just freezes and never completes the update. Our test db only has 8400 rows so this definitely shouldn't be a big problem.
Should we be using a stored procedure for this? What is the best approach to accomplish this?
We will have to do this to our date data for every new entry in the database. These entries could possibly happen 8400 rows at a time.
Column formats:
Year int
= 12Month int
= 4Day int
= 27Hour int
= 12Min int
= 0New column: smalldatetime
combinedDate = '2012-04-27 12:00:00 PM'
Upvotes: 0
Views: 446
Reputation:
As others mentioned, creating a computed column would be a better choice. Completely avoiding this approach would be even better. However, if cannot avoid this approach, here is the computed column expression that you could use. In the output section you can notice, that invalid values in month and min actually add up to display the correct date in future
Computed column expression:
(dateadd(year, (100) + [year],
dateadd(month, [month] - (1),
dateadd(day, [day] - (1),
dateadd(hour, [hour],
dateadd(minute, [min], (0))
)
)
)
)
)
Sample script:
CREATE TABLE dbo.myTable
(
[year] int NOT NULL
, [month] int NOT NULL
, [day] int NOT NULL
, [hour] int NOT NULL
, [min] int NOT NULL
, [smalldatetime] AS (dateadd(year,(100)+[year],dateadd(month,[month]-(1),dateadd(day,[day]-(1),dateadd(hour,[hour],dateadd(minute,[min],(0))))))) PERSISTED
);
INSERT INTO dbo.myTable ([year], [month], [day], [hour], [min]) VALUES
(12, 4, 27, 17, 34),
(12, 6, 12, 4, 8),
(11, 32, 12, 54, 87);
SELECT [year]
, [month]
, [day]
, [hour]
, [min]
, [smalldatetime]
FROM dbo.myTable;
Sample output:
year month day hour min smalldatetime
---- ----- --- ---- --- -----------------------
12 4 27 17 34 2012-04-27 17:34:00.000
12 6 -12 4 8 2012-05-19 04:08:00.000
11 32 12 54 87 2013-08-14 07:27:00.000
Upvotes: 1
Reputation: 1070
I agree that a computed column is the best approach.
Perhaps you should consider a different angle; instead of computing the datetime, rather compute the year/month/day/hour/minute via
Year as (DATEPART('yyyy', Time)) persisted not null,
Month as (DATEPART('m', Time)) persisted not null,
Day as (DATEPART('d', Time)) persisted not null,
Hour as (DATEPART('hh', Time)) persisted not null,
Min as (DATEPART('mi', Time)) persisted not null,
Time datetime not null
Link to DATEPART documentation
That way you will automatically have the other fields validated when updating the Time column.
Disclaimer: At the time of this writing I'm unsure if DATEPART is deterministic to use persisted.
Upvotes: 1
Reputation: 4399
Rather than trying to do the update from the C#
side, why don't you just specify a computed column
for combinedDate
. Take a look at the DATETIMEFROMPARTS
built-in function, it may be of use
EDIT
As was pointed out in the comments, DATETIMEFROMPARTS
is available only in SQL Server 2012, here is an alternative way to get a DATETIME from parts y
, m
, d
(assuming integers):
CAST(CAST(y AS varchar) + '-' + CAST(m AS varchar) + '-' + CAST(d AS varchar) AS DATETIME)
Upvotes: 0
Reputation: 116157
Why not use a computed column? That way you can be sure your year, month, day, hour, min and datetime fields are in sync (if you are obliged to keep the first).
Upvotes: 1