Question About DateCreated and DateModified Columns - SQL Server - sql-server

CREATE TABLE Customer
(
customerID int identity (500,20) CONSTRAINT
.
.
dateCreated datetime DEFAULT GetDate() NOT NULL,
dateModified datetime DEFAULT GetDate() NOT NULL
);
When i insert a record, dateCreated and dateModified gets set to default date/time. When i update/modify the record, dateModified and dateCreated remains as is? What should i do?
Obviously, i need to dateCreated value to remain as was inserted the first time and dateModified keeps changing when a change/modification occurs in the record fields.
In other words, can you please write a sample quick trigger? I don't know much yet...

You might want to look at creting an update trigger to update this value for you
Have a look at something like
CREATE TABLE Vals(
ID INT,
Val VARCHAR(10),
DateCreated DATETIME DEFAULT GetDate(),
DateUpdated DATETIME DEFAULT GetDate()
)
GO
CREATE TRIGGER Upd ON Vals
AFTER UPDATE
AS
UPDATE Vals
SET DateUpdated = GetDate()
FROM Vals INNER JOIN
inserted ON Vals.ID = inserted.ID
Go
INSERT INTO Vals (ID, Val) SELECT 1, 'A'
SELECT *
FROM Vals
GO
UPDATE Vals SET Val = 'B'
SELECT *
FROM Vals
GO
DROP TABLE Vals
GO

UPDATE
Customer
SET
... = NewValue,
dateModified = DEFAULT
WHERE
...
I'd use this rather than dateModified = GETDATE() so GETDATE() is only used once (say you want to change to GETUTCDATE() in future)
Or a trigger if you have multiple update paths...?

When i insert a record, dateCreated
and dateModified gets set to default
date/time. When i update/modify the
record, dateModified and dateCreated
remains as is? What should i do?
A Column default is only used when INSERTing and not by an UPDATE. The default will be used by the INSERT command if you do not supply the column or issue the DEFAULT keyword in the INSERT.
INSERT INTO Customer (col1, col2)
VALUES (..,..) ---get default for dateCreated & dateModified
INSERT INTO Customer (col1, col2,dateCreated)
VALUES (..,..,DEFAULT) ---get default for dateCreated & dateModified
INSERT INTO Customer (col1, col2,dateCreated,dateModified)
VALUES (..,..,DEFAULT,DEFAULT) ---get default for dateCreated & dateModified
INSERT INTO Customer (col1, col2,dateCreated,dateModified)
VALUES (..,..,'1/1/2010',DEFAULT) ---only get default for dateModified
INSERT INTO Customer (col1, col2,dateCreated,)
VALUES (..,..,'1/1/2010') ---only get default for dateModified
INSERT INTO Customer (col1, col2,dateCreated,dateModified)
VALUES (..,..,'1/1/2010','1/2/2010') ---no defaults for dateCreated & dateModifie
I like using a local variable set that the top of the procedure:
DECLARE #RunDate datetime
SET #RunDate=GETDATE()
I then use that within the procedure, so all changes (even on multiple tables) have the exact same date to the millisecond. I also prefer the dateModified column to allow nulls and not have a default, when it is inserted, it has been created not modified, I'll set the dateModified when it is actually modified.
then use:
UPDATE Customer
SET importantColumn=
,dateModified = #RunDate
WHERE ...
UPDATE CustomerPrice
SET importantColumn=
,dateModified = #RunDate
WHERE ...

#astander is right, you should just use an update trigger if you want this automated. My update triggers are slightly different (I use the 'inserted' virtual table). Here's one that should fit your schema (rename however you see fit):
CREATE TRIGGER [CustomerDateModifiedTrigger] ON [dbo].[Customer]
FOR UPDATE
AS
UPDATE Customer
SET dateModified = GETDATE()
FROM Customer c
INNER JOIN inserted i ON c.customerID = i.customerID

#Kronass, you don't have any idea about what uou are saying!
timestamp is the synonym for the rowversion data type and is subject to the behavior of data type synonyms. In DDL statements, use rowversion instead of timestamp wherever possible. For more information, see Data Type Synonyms (Transact-SQL).
The Transact-SQL timestamp data type is different from the timestamp data type defined in the ISO standard.
The timestamp syntax is deprecated. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.
rowversion (Transact-SQL) Is a data type that exposes automatically generated, unique binary numbers within a database. rowversion is generally used as a mechanism for version-stamping table rows. The storage size is 8 bytes. The rowversion data type is just an incrementing number and does not preserve a date or a time. To record a date or time, use a datetime2 data type.

1) Be sure to create the index for the primary key. (I just uncovered a mistake of this type recently.)
2) You can use one INSERT/UPDATE trigger instead of separate triggers at the price of a tiny loss of efficiency. If insert.DateCreated is null, then update Vals.DateCreated, otherwise update Vals.DateModified.

There is a datatype in SQL Server Called timestamp. which keep track of the row version for each time you modify the row.
Or if you want you can use a trigger and change the ModifiedDate Column.

Related

Clickhouse datetime comparison not working as expected

I am trying to compare the datetime, in clickhouse. But it's seems it's working in some wired way.
I have a column in my table which I want to compare with (now(),'UTC').
If the value of datetime in that column is less then the (now(),'UTC') Time than I wanna select data from that record.
I have created the table like
create table my_table (`mytime` DateTime, `data' [type]) ENGINE= engine
I want the queue like
Select data from my_table where mytime < toDateTime(now(), 'UTC')
Even if mytime > toDateTime(now(), 'UTC') it always considers mytime < toDateTime(now(), 'UTC')
It seems to me that something may up with the way you inserted data or your ClickHouse version has a bug.
The following example shows how to do what you are attempting in a way that works on my 19.15.4.10 server as expected to select only the earlier row. Note the select sleep() to ensure now() invocations are different.
drop table if exists my_table;
create table my_table (mytime DateTime, data String) engine = Memory;
insert into my_table values(now(), 'a');
select sleep(1);
insert into my_table values(toDateTime('2020-01-01 00:00:00', 'UTC'), 'b');
select * from my_table where mytime < now();
select * from my_table where mytime < toDateTime(now(), 'UTC');
On my server it does not matter whether you select now() or convert it. I also tried the way you originally defined the table and that works too. Hence the thought that something is up with your data.
The reason behind this issue was in clickhouse, it takes DateTime and DateTime('UTC') as different objects, therefore the comparison between them does not work as expected. Since I wanted to make the comparison with (now(),'UTC'), I have to change the type of
mytime as DateTime ('UTC').
I have to change the table as
create table my_table (`mytime` DateTime ('UTC'), `data' [type]) ENGINE= engine

SQL server GetDate in trigger called sequentially has the same value

I have a trigger on a table for insert, delete, update that on the first line gets the current date with GetDate() method.
The trigger will compare the deleted and inserted table to determine what field has been changed and stores in another table the id, datetime and the field changed. This combination must be unique
A stored procedure does an insert and an update sequentially on the table. Sometimes I get a violation of primary key and I suspect that the GetDate() returns the same value.
How can I make the GetDate() return different values in the trigger.
EDIT
Here is the code of the trigger
CREATE TRIGGER dbo.TR
ON table
FOR DELETE, INSERT, UPDATE
AS
BEGIN
SET NoCount ON
DECLARE #dt Datetime
SELECT #dt = GetDate()
insert tableLog (id, date, field, old, new)
select I.id, #dt, 'field', D.field, I.field
from INSERTED I LEFT JOIN DELETED D ON I.id=D.id
where IsNull(I.field, -1) <> IsNull(D.field, -1)
END
and the code of the calls
...
insert into table ( anotherfield)
values (#anotherfield)
if ##rowcount=1 SET #ID=##Identity
...
update table
set field = #field
where Id = #ID
...
Sometimes the GetDate() between the 2 calls (insert and update) takes 7 milliseconds and sometimes it has the same value.
That's not exactly full solution but try using SYSDATETIME instead and of course make sure that target table can store up datetime2 up to microseconds.
Note that you can't force different datetime regardless of precision (unless you will start counting up to ticks) as stuff can just happen at the same time wihthin given precision.
If stretching up to microseconds won't solve the issue on practical level, I think you will have to either redesign this logging schema (perhaps add identity column on top of what you have) or add some dirty trick - like make this insert in try catch block and add like microsecond (nanosecond?) in a loop until you insert successfully. Definitely not s.t. I would recommend.
Look at this answer: SQL Server: intrigued by GETDATE()
If you are inserting multiple ROWS, they will all use the same value of GetDate(), so you can try wrapping it in a UDF to get unique values. But as I said, this is just a guess unless you post the code of your trigger so we can see what you are actually doing?
It sounds like you're trying to create an audit trail - but now you want to forge some of the entries?
I'd suggest instead adding a rowversion column to the table and including that in your uniqueness criteria - either instead of or as well as the datetime value that is being recorded.
In this way, even if two rows are inserted with identical date/time data, you can still tell the actual insertion order.

Automatic adding current time in SQL Server 2012

I have table with a column of datatype time(4).
When I'm inserting values into the table I need to auto insert just the current time with milliseconds (without date) into that column. I have tried with time stamp, date time... but without any success.
If you want to get the current time in SQL Server 2012, just use the CAST operator to achieve this:
SELECT
CAST(SYSDATETIME() AS TIME(4))
This will get the current date & time, and cast this to just the time, as you need it.
To achieve automatic entry of time values when a new row is added, you can use the above expression in a default constraint. For example:
DECLARE #T AS table
(
SomeValue integer NOT NULL,
TheTime time(4) NOT NULL
DEFAULT CAST(SYSDATETIME() AS time(4))
);
INSERT #T (SomeValue)
VALUES (1);
SELECT
SomeValue,
TheTime
FROM #T;
As far as I understand, this is what you may be looking for:
SELECT GETDATE() 'Today',
CONVERT(TIME(4),GETDATE()) 'time_only'
You could use the above conversion in your insert statement as following:
INSERT INTO TABLEA (
column1
,column2
,record_insert_time
)
VALUES (
value1
,value2
,CONVERT(TIME(4), GETDATE())
);

T-SQL Select where Subselect or Default

I have a SELECT that retrieves ROWS comparing a DATETIME field to the highest available value of another TABLE.
The Two Tables have the following structure
DeletedRecords
- Id (Guid)
- RecordId (Guid)
- TableName (varchar)
- DeletionDate (datetime)
And Another table which keep track of synchronizations using the following structure
SynchronizationLog
- Id (Guid)
- SynchronizationDate (datetime)
In order to get all the RECORDS that have been deleted since the last synchronization, I run the following SELECT:
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords]
WHERE
[TableName] = '[dbo].[Person]'
AND [DeletionDate] >
(SELECT TOP 1 [SynchronizationDate]
FROM [dbo].[SynchronizationLog]
ORDER BY [SynchronizationDate] DESC)
The problem occurs if I do not have synchronizations available yet, the T-SQL SELECT does not return any row while it should returns all the rows cause there are no synchronization records available.
Is there a T-SQL function like COALESCE that I can use with DateTime?
Your subquery should look like something like this:
SELECT COALESCE(MAX([SynchronizationDate]), '0001-01-01')
FROM [dbo].[SynchronizationLog]
It says: Get the last date, but if there is no record (or all values are NULL), then use the '0001-01-01' date as start date.
NOTE '0001-01-01' is for DATETIME2, if you are using the old DATETIME data type, it should be '1753-01-01'.
Also please note (from https://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx)
Use the time, date, datetime2 and datetimeoffset data types for new work. These types align with the SQL Standard. They are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
EDIT
An alternative solution is to use NOT EXISTS (you have to test it if its performance is better or not):
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords] DR
WHERE
[TableName] = '[dbo].[Person]'
AND NOT EXISTS (
SELECT 1
FROM [dbo].[SynchronizationLog] SL
WHERE DR.[DeletionDate] <= SL.[SynchronizationDate]
)

Linq to SQL with INSTEAD OF Trigger and an Identity Column

I need to use the clock on my SQL Server to write a time to one of my tables, so I thought I'd just use GETDATE(). The problem is that I'm getting an error because of my INSTEAD OF trigger. Is there a way to set one column to GETDATE() when another column is an identity column?
This is the Linq-to-SQL:
internal void LogProcessPoint(WorkflowCreated workflowCreated, int processCode)
{
ProcessLoggingRecord processLoggingRecord = new ProcessLoggingRecord()
{
ProcessCode = processCode,
SubId = workflowCreated.SubId,
EventTime = DateTime.Now // I don't care what this is. SQL Server will use GETDATE() instead.
};
this.Database.Add<ProcessLoggingRecord>(processLoggingRecord);
}
This is the table. EventTime is what I want to have as GETDATE(). I don't want the column to be null.
And here is the trigger:
ALTER TRIGGER [Master].[ProcessLoggingEventTimeTrigger]
ON [Master].[ProcessLogging]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
SET IDENTITY_INSERT [Master].[ProcessLogging] ON;
INSERT INTO ProcessLogging (ProcessLoggingId, ProcessCode, SubId, EventTime, LastModifiedUser)
SELECT ProcessLoggingId, ProcessCode, SubId, GETDATE(), LastModifiedUser FROM inserted
SET IDENTITY_INSERT [Master].[ProcessLogging] OFF;
END
Without getting into all of the variations I've tried, this last attempt produces this error:
InvalidOperationException
Member AutoSync failure. For members to be AutoSynced after insert, the type must either have an auto-generated identity, or a key that is not modified by the database after insert.
I could remove EventTime from my entity, but I don't want to do that. If it was gone though, then it would be NULL during the INSERT and GETDATE() would be used.
Is there a way that I can simply use GETDATE() on the EventTime column for INSERTs?
Note: I do not want to use C#'s DateTime.Now for two reasons:
1. One of these inserts is generated by SQL Server itself (from another stored procedure)
2. Times can be different on different machines, and I'd like to know exactly how fast my processes are happening.
Bob,
It seems you are attempting to solve two different problems here. One of which has to do with a L2S error with an Instead Of trigger and another with using the date on the SQL Server box for your column. I think you might have problems with Instead of Triggers and L2S. You might want to try an approach that uses an After trigger, like this. I think this will solve both your problems.
ALTER TRIGGER [Master].[ProcessLoggingEventTimeTrigger]
ON [Master].[ProcessLogging]
AFTER INSERT
AS
BEGIN
UPDATE [Master].[ProcessLogging] SET EventTime = GETDATE() WHERE ProcessLoggingId = (SELECT ProcessLoggingId FROM inserted)
END
Don't use a trigger, use a defualt:
create table X
(id int identity primary key,
value varchar(20),
eventdate datetime default(getdate()))
insert into x(value) values('Try')
insert into x(value) values('this')
select * from X
It's much better.
Have you tried using a default value of (getdate()) for the EventTime colum?
You wouldn't then need to set the value in the trigger, it would be set automatically.
A default value is used when you don't explicitly supply a value, e.g.
INSERT INTO ProcessLogging (ProcessLoggingId, ProcessCode, SubId, LastModifiedUser)
SELECT ProcessLoggingId, ProcessCode, SubId, LastModifiedUser FROM inserted
Bob,
I see it is better to don't use triggers in SQL server; it have a lot of disadvantage and not recommended for database performance enhancements. Please check SQL Authority blog for more information about the Triggers problems.
You can achieve what you want without Triggers using the following steps:
Change Eventime column to allow null
Set Eventtime column Default Value to GetDate(). So it always will have a the current insertion value.
Don't set Eventtime value to DateTime.Now from your LinqToSQL code, so it will take the default value in the SQL Server.

Resources