Continuosly get stream of each insertions from SQL Server table - c#

I want to monitor insertions in an SQL Server table. Like two columns UserID and Activity from a table (userData) so that as soon as the insertion happens to this table, I get the values that were inserted and passed to C#.
I want to use each insertion for comparison like comparing each insertion with some value and take actions upon them.
PS. I know how to get data from SQL Server and insert data to SQL Server table using C#. But don't know how to achieve it on a real-time basis to take decisions upon them.

You can use SqlDependency class and use it's OnChange event. Go through the linked MSDN document to see an example on how.
dependency.OnChange+=new
OnChangeEventHandler(OnDependencyChange);

Create an Insert Trigger
CREATE TRIGGER [dbo].[userDataInsert]
ON [dbo].[userData]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON
select *
from inserted
-- do whatever you need with inserted
END

Use can also look at SqlTableDependency. It is a c# component raising events when a record is changes. You can find more detail at: https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency
SqlTableDependency is a high-level C# component used to audit, monitor and receive notifications on SQL Server's record table changes. For any record table change, as insert, update or delete operation, a notification containing values for the record changed is delivered to SqlTableDependency. This notification contains insert, update or delete record values.
This table record tracking change system has the advantage to avoid a select to retrieve updated table record, because the updated table values record is delivered by notification.

Related

getting "DateTime" of the last change in rows in a table in SQL Server?

Is there any way to find "DateTime" of the last change in rows in a table in SQL Server?
The changes (Insert / Update) are submitted by another windows application
And all I have in this table is insert_Date and there is no update_Date (and I can't add any columns or use triggers)
I've tried some queries, but all I got was the number of "User Updates" in a table, not the IDs of modified rows!
I want to get rows which are modified or inserted after a specific DateTime
If the information isn't stored in the table (or in another one by using a trigger for example) then it's impossible to track which rows were inserted after a determined datetime. You might find the time the last operation was executed at a table/index level (by querying sys.dm_db_index_usage_stats) but not at a record level.
You can't find data that doesn't exist!

Insert/Update whole DataTable into database table C#

I am facing an issue I hope to get it solved by here. I have 3 different tables in a DataSet and I want to insert it in the database table.
I know I can do this using SqlBulkCopy but there is a catch and that is I want to check if the data already exists in the database then I want it to get updated instead of insert.
And if the data doesn't exist in the database table, I want to insert it then. Any help on this would be appreciated.
I know I can iterate it through each record and then fire a procedure which will check for its existence if it exists den update or else insert. But the data size is huge and iterating through each record would be a time taking process, I don't want to use this approach.
Regards
Disclaimer: I'm the owner of the project Bulk Operations
This project allows to BulkInsert, BulkUpdate, BulkDelete, and BulkMerge (Upsert).
Under the hood, it does almost what #marc_s have suggested (Use SqlBulkCopy into a temporary table and perform a merge statement to insert or update depending on the primary key).
var bulk = new BulkOperation(connection);
bulk.BulkMerge(dt);

How to pull a SQL Table entry based on highest IDENTITY entry and update two columns

I'm not well versed in SQL operations, and would like some help with a task I need to complete in code. I have written a cloud based app that accesses a SQL table containing test results - device ID's, serial numbers, test results etc.
There is a use-case where someone in the field would activate a menu where an update to this table occurs. When the device test result table is updated, I want to store the OLD information in a device test history table. This way, we can go back and see what was changed over time.
So I need to pull all the columns from the TestedDevice table, insert them into TestedDeviceHistory table, and include some additional information; the current date and the operator's id. (these are two new columns found only in TestedDeviceHistory)
At first, I'm using a SELECT INTO command, as follows:
SELECT *
INTO dbo.TestedDevicesHistory
FROM dbo.TestedDevices
WHERE CertificateID = #cert
Then I'm attempting this (obviously broken) SQL command:
UPDATE dbo.TestedDeviceHistory
SET Caller = #caller,
RecordDate = #date
WHERE DeviceHistoryID = MAX(DeviceHistoryID)
Notes:
DeviceHistoryID is an IDENTITY integer column, so it's unique for each entry made in the history table.
CertificateID is unique in the TestedDevices table. It is expected NOT to be unique in the history table.
The code is written in C# 4.5
Maybe this is a case for a stored procedure, which I have never attempted to create or use. Or, perhaps the use of a cursor? Don't know! This is why I'm humbly asking for the more experienced with SQL to help :)
Not clear on if you only want to assign the Caller and RecordDate to the most recent record, or if it could be assigned to all the history records.
For all records, I believe you can do something like
SELECT *, #caller AS Caller, #date AS RecordDate INTO dbo.TestedDevicesHistory
FROM dbo.TestedDevices WHERE CertificateID=#cert

Move data to historical table after delete

I would like to know what is the best approach for creating a historical table for some table and automatically move deleted rows to this new table with same columns + deleted time.
For example:
When I delete a row from a PRODUCT table it will move to PRODUCT_H table with deleted time column.
Thank you for your time.
The best option is set trigger in database something like that :
CREATE TRIGGER movetohistorical
ON dbo.PRODUCT
FOR DELETE
AS
INSERT Product_H
SELECT * FROM dbo.PRODUCT
WHERE PRODUCT.id IN(SELECT deleted.id FROM deleted)
GO
The easisest way to do it is to implement a trigger in the database.
You can create the trigger using CREATE TRIGGER.
You don't have to worry about the trigger in your application code.
The trigger should be an AFTER DELETE trigger, which will execute whenever a row (or several rows) is (are) deleted.
You can read this article which implements nearly what you need (it implements a history table, but doesn't record the current datetime): SQL Server: Coding the After Delete Trigger in SQL Server. In fact, you have to make only a little change. In the sample, the insertion in the histroy table uses SELECT * FROM .... To do what you need, you simply have to add the GETDATE() function like this: SELECT *, GETDATE() FROM .... of course the destination table must have this date column at the end (if something goes wrong, simply specify the column names, instead of using the star).
Any other option will imply adding code to your application, and will require extra communication between your app and the SQL Server.

How to automatically truncate string when do bulk insert?

I want to insert many rows (constructed from Entity Framework objects) to SQL Server. The problem is, some of string properties have length exceeded length of column in database, which causes an exception, and then all of rows will unable to insert into database.
So I wonder that if there is a way to tell SqlBulkCopy to automatically truncate any over-length rows? Of course, I can check and substring each property if it exceeds the limited length, before insert it in to a DataTable, but it would slow down the whole program.
Always use a staging/load table for bulk actions.
Then you can process, clean, scrub etc the data before flushing to the real table. This includes, LEFTs, lookups, de-duplications etc
So:
Load a staging table with wide columns
Flush from staging to "real" table using INSERT realtable (..) SELECT LEFT(..), .. FROM Staging
Unfortunately there is no direct way of doing that with SqlBulkCopy. SQL Bulk Inserts are by nature almost "dumb" but that's why they are so fast. They aren't even logged (except capturing SqlRowsCopied event) so if something fails, there's not much information. What you're looking for would in a way, be counter to the purpose of this class
But there can be 2 possible ways:
You can try using SqlBulkCopyOptionsEnumeration (passed to SqlBulkCopy() Constructor) and use SqlBulkCopyOptions.CheckConstraints (Check constraints while data is being inserted. By default, constraints are not checked.).
Or you can use SqlBulkCopyOptions.FireTriggers Enumeration (When specified, cause the server to fire the insert triggers for the rows being inserted into the database.) and handle the exception in SQL Server Insert Trigger.
Try Using SQLTransaction Class while using SQLBulkCopy Class

Categories