Is it possible to have same SYSDATETIME result for 2 transactions - sql-server-2012

According to documentation, the precision of SYSDATETIME() function in sql server is approximately 100 nanoseconds. I have seen that just like GETDATE(), the SYSDATETIME function also returns the same result within a transaction. Also, the time differs in two batches separated by GO.
Now my real question is, is it safe to assume that two transactions will always have different SYSDATETIME, no matter how close to concurrency they can reach within the same server/database instance, irrespective of the number of cores/hardware, the server has?
Background: I am trying to implement audit on an existing database using temporal tables. We are already keeping a modified by column in all tables. But we cannot identify who deleted a record using temporal tables. So I was thinking of dumping user id (end user's id) into a table for all transactions. So, if the time matches with temporal table, I might be able to identify the user based on date-time.

First i need to inform you that GETDATE() and SYSDATETIME gives the different datetime formate. SYSDATETIME() will give you result as follow - 2019-06-03 16:11:07.3683245 and GETDATE() will - 2019-06-03 16:11:07.367. Now the things is you need to add two columns in a table for which user updated the records and what time. And if you are not using any time consuming process between update temporal table and update main table than it will get same time both. But if any reason it will take time to update both record than it can be different time in both table.
You can use Declare method in sql to have same datetime in both table. No problem when it will update at different time. you can use Declare method to get datetime same as like follow.
Declare #date Datetime2 = SYSDATETIME()
Select #Date
You can use #Date When you are updating datetime in query.
I hope it will work.

Related

SQL Server, Efficient way to query multiple tables for a specific day of data

We have started saving the daily change data for a bunch of tables. We first put in all of the original data and than the change data with start and end dates for each table record (So not all records are saved each day just changed records). So to pull the data for a specific date I have to look at the beginning and end dates (end date might be null) and pull the MAX begin date to get the right records.
SELECT *
FROM dbo.DIM_EX_NAME_MASTER AS DEXNM
INNER JOIN
(SELECT APPID, MAX(DW_RECORD_START) AS StartDate
FROM dbo.DIM_EX_NAME_MASTER
WHERE (DW_RECORD_START < '4/4/2020') AND (DW_RECORD_END > '4/4/2020')
OR (DW_RECORD_START < '4/4/2020') AND (DW_RECORD_END IS NULL)
GROUP BY APPID) AS INNER_DEXNM ON DEXNM.APPID = INNER_DEXNM.APPID AND DEXNM.DW_RECORD_START = INNER_DEXNM.StartDate
So that's not so bad for one table but we want to build a report with a query that pulls from 25 tables with subqueries where the user selects the date to pull for.
That's going to be some really messy sql. Ideally I would like to create a view for each table and pass in the date as a parameter but SQL server doesn't allow for parameterized views.
Anyone have any ideas on how I can build multi-table date based queries without adding all of this extra sql per table?
Thanks for any help you can give!
SQL server doesn't allow for parameterized views.
No, but SQL Server does support user-defined table-valued functions.
This is pretty much exactly what you are asking for -- they can accept a date parameter and return the results as a table.

SQL - Incremental insert using SSIS?

I have quite a large table that I need to import into my BI environment for reporting. I have an SSIS package that calls a stored procedure runs every 20 minutes to extract data from source and populate it into my table. The earliest date on the source table is 01-January-2012.
What I would like is for the first time the package runs it will import all the data from source for the month of January 2012. The next time it runs it will populate all the data for February 2012 and so on.
The below is the query I would use to extract the data - this is based on Created and Modified Dates
Select ID, Name, Company, Job, HRID, PayID, CreatedOn, ModifiedOn
from dbo.HRDetails
where CreatedOn between #MonthStart and #MonthEnd
or ModifiedOn between #MonthStart and #MonthEnd
I just need help on how I would make this incremental to pick up the data month on month dynamically?
Any help would be appreciated
-Jess
In your stored procedure, pull the current max date from the loaded table and set your variables based on that:
DECLARE #DateLoaded = ISNULL((SELECT MAX(dateField) FROM yourLoadedTable),'20120101') --MAX date loaded
DECLARE #MonthStart = DATEADD(DAY,1,EOMONTH(#DateLoaded)) --End of max loaded month, plus 1 day to get first day of next month
DECLARE #MonthEnd = EOMONTH(#DateLoaded, 1) --End of next month
Select ID, Name, Company, Job, HRID, PayID, CreatedOn, ModifiedOn
from dbo.HRDetails
where CreatedOn between #MonthStart and #MonthEnd
or ModifiedOn between #MonthStart and #MonthEnd
I like this type of approach because it's self-repairing if a pull fails, even if you've missed a few months before noticing the issue.
I would do this by creating a metadata table in SQL Server.
Each time the package runs, insert a date/identifier into that table to note that the task has been completed for that month (as your final package step). For the first package step, you would use that table to get the next month that hasn't been completed (you would store this in a variable for use in the later insert). (You would also have a default/start month, which would be used if the table is empty.)
Instead of using dates, you can use Change Tracking to identify all keys modified since the last update, even deleted ones. The feature is available in all versions and editions since 2005, even Express.
Work with Change Tracking (SQL Server) shows how you can retrieve any changes made to a table since the last sync operation.
This query will return all modified rows and the reason they were modified from the Product table since the version specified in last_synchronization_version. Any deleted rows will appear with D in the SYS_CHANGE_OPERATION field :
SELECT
CT.ProductID, P.Name, P.ListPrice,
CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
CT.SYS_CHANGE_CONTEXT
FROM
SalesLT.Product AS P
RIGHT OUTER JOIN
CHANGETABLE(CHANGES SalesLT.Product, #last_synchronization_version) AS CT
ON
P.ProductID = CT.ProductID
The sync version you'll use for the next iteration should be retrieved before selecting changes. You can retrieve it with :
SET #synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();
This query is very fast because it joins on the table's primary keys.
Another nice thing about this is that it doesn't care if you forget to run it - it will still pull all changes since the last execution. Running this more frequently results in better performance since the query has fewer changes to return.

DateTime Column Set to Past Date

We have a SQL Server database for storing our transaction data. In each of the table, we have a LastUpdatedOn column which gets populated by using the GETDATE() function.
What we are seeing is when we have bulk update operations on these tables, at the end of bulk operation, the timestamp in the LastUpdatedOn column will be past date.
Eg: if the update operation started at time 10:00:00.000 AM, the GETDATE() function will select that as the time and the LastUpdatedOn column will be populated with datetime as 10:00:00.000 AM. If the script takes 30 seconds to execute, the at 10:00:30.000 AM, when the scripts completes the executed, the lastupdateon column will be populated with a past date.
See the sample script below:
SELECT TOP 100000 *
INTO #tmp
FROM dbo.Test
BEGIN TRAN
UPDATE L
SET l.lastupdateon = getdate()
FROM dbo.Test L
JOIN #tmp T ON T.entitykey = L.entitykey
COMMIT TRAN
The issue which we are running into is, we have a delta operation that has from and to dates. This operation will return any records that got updated between the from and to date. In this case, if delta operation gets called at 10:00:15.000 AM, the records that got updated as a part of the script will not be pulled even though the record got updated at 10:00:00.000 AM. These records will never get pulled.
Is there any solution for this problem other than making the transaction serializable?
Regards,
John
The fundamental problem is that the update takes time, so there will always be a delay between when you tell SQL Server to write a value to the table and when that value is committed and visible to others.
You need to address this in your delta operation. Is only one process writing to the table? If so, newly committed rows will always have a LastUpdatedOn value that is after everything else in the table. In this case, the delta operation should keep track of the max LastUpdatedOn value it got last time and look for anything greater than that.

SQL Server query to get the difference between two dates in two different columns

I would like to write a SQL Server query which should get the difference between two dates (i.e. dates are available in two columns named "Start date" and "End date"). I would like to find the difference between two dates in these two different columns and update in another column as "Expired" if the difference is -1 or below. Most importantly: The time should start from the specified start date and it should check periodically.
To find the differential between two date values you use the DATEDIFF() function.
Also, depending on your requirements, you can set this up in your table as a Computed Column. That way any changes to the component columns in the computed column's definition will automatically update the computed column to reflect the new values.
With the PERSISTED keyword you can also allow the computed column to be indexed on.
Check the documentation here for more details: https://technet.microsoft.com/en-us/library/ms191250%28v=sql.105%29.aspx
This is based on what I think you are trying to do, it's not exactly clear.
I don't think you want to add a column to your table to identify what is expired because that column would be dependant on the "End Date" column as well as the primary key which would violate the 3rd normal form. It really shouldn't be needed because you can query out which ones are expired at any time. I can't really think of a scenario where you would need to have a column that indicates expiry. You can create a query like others mentioned to display (not create) another column that marks the expired rows, or you can simply display only the ones expired, or it might make more sense to move them to a different table.
SET IDENTITY_INSERT ExpiredTableName ON
INSERT INTO ExpiredTableName (Column1, Column2, StartDate, EndDate)
SELECT *
FROM TableName
WHERE DATEDIFF(day, InvoiceDate, '2015-04-20') >0
Identity Insert is for auto-generated keys only.
You can run your queries at regular time intervals like was already mentioned.
You can use DATEDIFF and case when like this:
update table set expColumn = case when DATEDIFF(day,start_date,end_date) > 0
then 'Expired' end FROM table
Hope this helps.

Storing time values in a database and getting the difference between two time fields

I am working on an application the stores time values in a database e.g Expected time of Arrival and actual time of arrival. What is the best way of storing these fields in a database?
What SQL query can I use to obtain the time difference between the two fields?
If you're on SQL Server 2008, use the TIME datatype. Declare those two fields
ExpectedTimeOfArrival TIME(7),
ActualTimeOfArrival TIME(7)
Read up on how to manipulate the TIME datatype here.
Once you have those two fields in place, you could add a computed column to your table that calculates the difference between those two, e.g. in minutes:
ALTER TABLE dbo.YourTable
ADD TimeDifference AS DATEDIFF(MINUTE, ActualTimeOfArrival, ExpectedTimeOfArrival)
and then you could query o that new column TimeDifference as if it were a normal, regular table column.