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.
Related
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.
My goal is to pull the last modified date and time for a table in SQL server (MS SQL SERVER 2008 R2), when I say last modified date and time, I specifically meant the changes of values for the records of that table. For example, value added, deleted, or updated. Not changes such as structural change for the table.
Assuming my DB name is MyDB.
Assuming my table name is MyTable.
So I used the following query and it did work every time I changed a value for a record in the table, and reflects the correct time for the change:
SELECT last_user_update from sys.dm_db_index_usage_stats where database_id = DB_ID('MyDB') and object_id = object_id('MyDB.dbo.Mytable')
My question now - Is this query the correct way to meet my goal? Because I sort of came up with this query by trail and error so I need some confirmation. Also, does this query also reflect other changes for the table such as structural changes? If so, is there a better query that is cleaner and only reflects value changes within the table?
MSDN States: The user_updates counter indicates the level of maintenance on the index caused by insert, update, or delete operations on the underlying table or view.
https://msdn.microsoft.com/en-us/library/ms188755.aspx
So its probably OK.
However you could probably put a LastModifiedDateTime field on the DB and set it during an operation and then select the MAX value for this.
EDIT: As per comments:
CREATE TRIGGER LastUpdateTrigger
ON sourceTable
AFTER INSERT, UPDATE, DELETE
AS
IF NOT EXISTS(SELECT * FROM destTable WHERE TableName = 'sourceTable')
BEGIN
INSERT INTO destTable (LastUpdateDateTime, TableName)
VALUES (GETDATE(), 'sourceTable')
END
ELSE
BEGIN
UPDATE destTable SET LastUpdateDateTime = GETDATE()
WHERE Tablename = 'sourceTable'
END
Also put table name in destTable to track updates accross tables in same database.
I have a simple database named customer with a single table data.I want to check if a customer name exits in the database,if then i want to delete it.I'm using MYSQL Connector for this.
EDIT:
I want to make sure the value is present before deleting to display
a simple user message.
Why not just deleting it?
DELETE FROM customers WHERE customer_name = 'John Smith';
If it exists, it will be deleted. Otherwise no rows will be affected.
EDIT:
If you need a more complicated process, then I recommend (in order):
creating ON DELETE FOR EACH ROW trigger, that will auto update flags upon deletion;
developing a function/procedure for this purpose;
performing a set of actions within a transaction block, like:
START TRANSACTION;
UPDATE flag_table SET is_deleted = 1 WHERE customer_name = 'John Smith';
DELETE FROM customers WHERE customer_name = 'John Smith';
COMMIT;
It would be easier to answer if you could provide more details on your design.
you can use a trigger for this purpose, mysql will delete if any repetation is found on insertion.
I'm stuck on a little problem concerning database.
Once a month I get a XML file with customer information (Name, address, city,etc.). My primary key is a customer number which is provided in the XML file.
I have no trouble inserting the information in the database;
var cmd = new SqlCommand("insert into [customer_info]
(customer_nr, firstname, lastname, address_1, address_2, address_3.......)");
//some code
cmd.ExecuteNonQuery();
Now, I would like to update my table or just fill it with new information. How can I achieve this?
I've tried using TableAdapter but it does not work.
And I'm only permitted to add one XML because I can only have one customer_nr as primary key.
So basically how do I update or fill my table with new information?
Thanks.
One way would be to bulk insert the data into a new staging table in the database (you could use SqlBulkCopy for this for optimal insert speed). Once it's in there, you could then index the customer_nr field and then run 2 statements:
-- UPDATE existing customers
UPDATE ci
SET ci.firstname = s.firstname,
ci.lastname = s.lastname,
... etc
FROM StagingTable s
INNER JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
-- INSERT new customers
INSERT Customer_Info (customer_nr, firstname, lastname, ....)
SELECT s.customer_nr, s.firstname, s.lastname, ....
FROM StagingTable s
LEFT JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
WHERE ci.customer_nr IS NULL
Finally, drop your staging table.
Alternatively, instead of the 2 statements, you could just use the MERGE statement if you are using SQL Server 2008 or later, which allows you to do INSERTs and UPDATEs via a single statement.
If I understand your question correctly - if the customer already exists you want to update their information, and if they don't already exist you want to insert a new row.
I have a lot of problems with hard-coded SQL commands in your code, so I would firstly be very tempted to refactor what you have done. However, to achieve what you want, you will need to execute a SELECT on the primary key, if it returns any results you should execute an UPDATE else you should execute an INSERT.
It would be best to do this in something like a Stored Procedure - you can pass the information to the stored procedure at then it can make a decision on whether to UPDATE or INSERT - this would also reduce the overhead of making several calls for your code to the database (A stored procedure would be much quicker)
AdaTheDev has indeed given the good suggestion.
But in case, you must insert/update from .NET code then you can
Create a stored procedure that will handle insert/update i.e. instead of using a direct insert query as command text, you make a call to stored proc. The SP will check if row exists or not and then update (or insert).
User TableAdapter - but this would be tedious. First you have to setup both insert & update commands. Then you have to query the database to get the existing customer numbers and then update the corresponding rows in the datatable making the Rowstate as Updated. I would rather not go this way.
so I have an old database that I'm migrating to a new one. The new one has a slightly different but mostly-compatible schema. Additionally, I want to renumber all tables from zero.
Currently I have been using a tool I wrote that manually retrieves the old record, inserts it into the new database, and updates a v2 ID field in the old database to show its corresponding ID location in the new database.
for example, I'm selecting from MV5.Posts and inserting into MV6.Posts. Upon the insert, I retrieve the ID of the new row in MV6.Posts and update it in the old MV5.Posts.MV6ID field.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually? I'm using SQL Server 2005, dev edition.
The key with migration is to do several things:
First, do not do anything without a current backup.
Second, if the keys will be changing, you need to store both the old and new in the new structure at least temporarily (Permanently if the key field is exposed to the users because they may be searching by it to get old records).
Next you need to have a thorough understanding of the relationships to child tables. If you change the key field all related tables must change as well. This is where having both old and new key stored comes in handy. If you forget to change any of them, the data will no longer be correct and will be useless. So this is a critical step.
Pick out some test cases of particularly complex data making sure to include one or more test cases for each related table. Store the existing values in work tables.
To start the migration you insert into the new table using a select from the old table. Depending on the amount of records, you may want to loop through batches (not one record at a time) to improve performance. If the new key is an identity, you simply put the value of the old key in its field and let the database create the new keys.
Then do the same with the related tables. Then use the old key value in the table to update the foreign key fields with something like:
Update t2
set fkfield = newkey
from table2 t2
join table1 t1 on t1.oldkey = t2.fkfield
Test your migration by running the test cases and comparing the data with what you stored from before the migration. It is utterly critical to thoroughly test migration data or you can't be sure the data is consistent with the old structure. Migration is a very complex action; it pays to take your time and do it very methodically and thoroughly.
Probably the simplest way would be to add a column on MV6.Posts for oldId, then insert all the records from the old table into the new table. Last, update the old table matching on oldId in the new table with something like:
UPDATE mv5.posts
SET newid = n.id
FROM mv5.posts o, mv6.posts n
WHERE o.id = n.oldid
You could clean up and drop the oldId column afterwards if you wanted to.
The best you can do that I know is with the output clause. Assuming you have SQL 2005 or 2008.
USE AdventureWorks;
GO
DECLARE #MyTableVar table( ScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());
It still would require a second pass to update the original table; however, it might help make your logic simpler. Do you need to update the source table? You could just store the new id's in a third cross reference table.
Heh. I remember doing this in a migration.
Putting the old_id in the new table makes both the update easier -- you can just do an insert into newtable select ... from oldtable, -- and the subsequent "stitching" of records easier. In the "stitch" you'll either update child tables' foreign keys in the insert, by doing a subselect on the new parent (insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild) or you'll insert children and do a separate update to fix the foreign keys.
Doing it in one insert is faster; doing it in a separate step meas that your inserts aren't order dependent, and can be re-done if necessary.
After the migration, you can either drop the old_id columns, or, if you have a case where the legacy system exposed the ids and so users used the keys as data, you can keep them to allow use lookup based on the old_id.
Indeed, if you have the foreign keys correctly defined, you can use systables/information-schema to generate your insert statements.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually?
Since you wouldn't want to do it manually, but automatically, create a trigger on MV6.Posts so that UPDATE occurs on MV5.Posts automatically when you insert into MV6.Posts.
And your trigger might look something like,
create trigger trg_MV6Posts
on MV6.Posts
after insert
as
begin
set identity_insert MV5.Posts on
update MV5.Posts
set ID = I.ID
from inserted I
set identity_insert MV5.Posts off
end
AFAIK, you cannot update two different tables with a single sql statement
You can however use triggers to achieve what you want to do.
Make a column in MV6.Post.OldMV5Id
make a
insert into MV6.Post
select .. from MV5.Post
then make an update of MV5.Post.MV6ID