I have a table in SQL Server database. It has a column testrownum. I want to update the testrownum column to be rownum whenever row is created in the table automatically.
Is there any setting that I can turn on to achieve this?
Perhaps it is best to get a row number at the time you SELECT your data, by using the ROW_NUMBER() function.
As others have pointed out (comments section) the data in a table is essentially unordered. You can however assign a row number for a certain ordering when you select data as follows (suppose a table that only has one column being name):
SELECT
name,
rownr=ROW_NUMBER() OVER(ORDER BY name)
FROM
name_table
You can create trigger function.
Trigger is a function which is called every time data is insert, update or delete from table (you can specify when you want your function to be called when creating trigger). So you can add two triggers, one for insert and one for delete and just increment/decrement value you want.
Related
I need a column to be dynamic as such that a column DaysToExpiration is calculated based on the number of days between now and a date column Expiration Date.
My plan was to add a trigger that fires on a SELECTstatement of the table.
Is this possible? How?
Is there a better way to go about this?
You say "My plan was to add a Trigger that Fires on a SELECT statement of the table."
In that case why have a column at all, why not just select it in your final query?
Select DateDiff(day,getdate(),ExpirationDate) AS [DaysToExpiration]
If it must be persisted and stored in a column then you can make it a computed column as suggested in the comments. Or you could have the table trigger on UPDATE/INSERT so when the ExpirationDate is inserted or updated it sets the DaysToExpiration column to the result of the provided code.
No there is no provision of having trigger on SELECT operation. You can use stored procedure which takes parameters that are fetched from SELECT query and call this procedure after desired SELECT query.
I am very new to SQL and SQL server, would appreciate any help with the following problem.
I am trying to update a share price table with new prices.
The table has three columns: share code, date, price.
The share code + date = PK
As you can imagine, if you have thousands of share codes and 10 years' data for each, the table can get very big. So I have created a separate table called a share ID table, and use a share ID instead in the first table (I was reliably informed this would speed up the query, as searching by integer is faster than string).
So, to summarise, I have two tables as follows:
Table 1 = Share_code_ID (int), Date, Price
Table 2 = Share_code_ID (int), Share_name (string)
So let's say I want to update the table/s with today's price for share ZZZ. I need to:
Look for the Share_code_ID corresponding to 'ZZZ' in table 2
If it is found, update table 1 with the new price for that date, using the Share_code_ID I just found
If the Share_code_ID is not found, update both tables
Let's ignore for now how the Share_code_ID is generated for a new code, I'll worry about that later.
I'm trying to use a merge query loosely based on the following structure, but have no idea what I am doing:
MERGE INTO [Table 1]
USING (VALUES (1,23-May-2013,1000)) AS SOURCE (Share_code_ID,Date,Price)
{ SEEMS LIKE THERE SHOULD BE AN INNER JOIN HERE OR SOMETHING }
ON Table 2 = 'ZZZ'
WHEN MATCHED THEN UPDATE SET Table 1.Price = 1000
WHEN NOT MATCHED THEN INSERT { TO BOTH TABLES }
Any help would be appreciated.
http://msdn.microsoft.com/library/bb510625(v=sql.100).aspx
You use Table1 for target table and Table2 for source table
You want to do action, when given ID is not found in Table2 - in the source table
In the documentation, that you had read already, that corresponds to the clause
WHEN NOT MATCHED BY SOURCE ... THEN <merge_matched>
and the latter corresponds to
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
Ergo, you cannot insert into source-table there.
You could use triggers for auto-insertion, when you insert something in Table1, but that will not be able to insert proper Shared_Name - trigger just won't know it.
So you have two options i guess.
1) make T-SQL code block - look for Stored Procedures. I think there also is a construct to execute anonymous code block in MS SQ, like EXECUTE BLOCK command in Firebird SQL Server, but i don't know it for sure.
2) create updatable SQL VIEW, joining Table1 and Table2 to show last most current date, so that when you insert a row in this view the view's on-insert trigger would actually insert rows to both tables. And when you would update the data in the view, the on-update trigger would modify the data.
Here is the following situation:
I have a table of StudentsA which needs to be synchronized with another table, on a different server, StudentsB. It's a one-way sync from A to B.
Since the table StudentsA can hold a large number of rows, we have a table called StudentsSync (on the input server) containing the ID of StudentsA which have been modified since the last copy from StudentsA to StudentsB.
I made the following SSIS Data Flow task:
The only problem is that I need to DELETE the row from StudentsSync after a successful copy or update. Something like this:
Any idea how this can be achieved?
It can be achieved using 3 methods
1.If your target table in OutputDB has TimeStamp columns such as Create and modified TimeStamp then rows which have got updated or inserted can be obtained by writing a simple query. You need to write the below query in the execte sql task in Control Flow to delete those rows in Sync Table .
Delete from SyncTable
where keyColumn in (Select primary_key from target
where ModifiedTimeStamp >= GETDATE() or (ModifiedTimeStamp is null
and CreateTimeStamp>=GETDATE()))
I assume StudentsA's primary key is present in Sync table along with primary key of Target table. The above condition basically checks, if a new row is added then CreateTimeStamp column will have current date and modifiedTimeStamp will be null else if the values are updated then the modifiedTimeStamp will have current date
The above query will work if you have TimeStamp columns in your target table which i feel should be there if your loading data into Data Warehouse
2.You can use MERGE syntax to perform the update and insert in Control Flow with Execute SQL Task.No need to use Data Flow Task .The below query can be used even if you don't have any TimeStamp columns
DECLARE #Output TABLE ( ActionType VARCHAR(20), SourcePrimaryKey INT)
MERGE StudentsB AS TARGET
USING StudentsA AS SOURCE
ON (TARGET.CommonColumn = SOURCE.CommonColumn)
WHEN MATCHED
THEN
UPDATE SET TARGET.column = SOURCE.Column,TARGET.ModifiedTimeStamp=GETDATE()
WHEN NOT MATCHED BY TARGET THEN
INSERT (col1,col2,Col3)
VALUES (SOURCE.col1, SOURCE.col2, SOURCE.Col3)
OUTPUT $action,
INSERTED.PrimaryKey AS SourcePrimaryKey INTO #Output
Delete from SyncTable
where PrimaryKey in (Select SourcePrimaryKey from #Output
where ActionType ='INSERT' or ActionType='UPDATE')
The code is not tested as i'm running out of time .but at-least it should give you a fair idea how to proceed . .For furthur detail on MERGE syntax read this and this
3.Use Multicast Component to duplicate the dataset for Insert and Update .Connect a MULTICAST to lookmatch output and another multicast to Lookup No match output
Add a task after "Update existing entry" and after "Insert new entry" to add the student ID to a variable which will contain the list of IDs to delete.
Enclose all of the tasks in a sequence container.
After the sequence container executes add a task to delete all the records from the sync table that are in that variable you've been populating.
Currently I have a Item table and a ItemWaste table.
Both tables will have some fields, such as: Name, Amount, etc. But the ItemWaste table will have one more field, which is the TimeWasted.
I wish to automatically insert the DELETED item from the Item table to the ItemWaste table, and at the same time insert the deletion time to the TimeWasted field.
I got no idea how to do this, is it using trigger???
Hope can get some help here... Appreciate any feedback... Thanks....
Sure - not a problem.
You need a basic AFTER DELETE trigger - something like this:
CREATE TRIGGER trg_ItemDelete
ON dbo.Item
AFTER DELETE
AS
INSERT INTO dbo.ItemWaste(Name, Amount, TimeWasted)
SELECT d.Name, d.Amount, GETDATE()
FROM Deleted d
That's all there is! One point to remember: the trigger is called once per batch - e.g. if you delete 100 rows at once, it will be called once and the pseudo table Deleted will contain 100 rows. The trigger is not called once per row (a common misconception).
Yes, simply by writting a trigger you can insert a row when an delete action is performed in another table, have a look at Triggers
I want to do some calculations when my table data is changed. However, I am updating my table manually and copy pasting about 3000 rows in once. That makes my trigger work 3000 times, but I want it to do the trigger only once.
Is there a way to do that ?
Thanks.
What's your statement?
If you have multiple inserts then it will fire for each insert you are running. If you want it to execute only once for multiple inserts you must:
Write your insert on a single statement such as insert into foo select * from bar
Your trigger can't be for each row
Other possibility might be:
Disable the trigger
Perform your insertions
Put the trigger code in a stored procedure
Run your stored procedure
If by 'manually' you mean you are copying and pasting into some User Interface tool (like an Access dataGrid) or something like that, then the tool may be issuing one insert statement per row, and in that case you are out of luck the database trigger will be executed once per insert statement. As other answers have mentioned, if you can insert the rows directly into the database, using a single insert statement, then the trigger will only fire once.
The issue is caused because you are manually pasting the 3000 rows. You really have 2 solutions. You can turn off the trigger by doing this:
ALTER TABLE tablename DISABLE TRIGGER ALL
-- do work here
ALTER TABLE tablename ENABLE TRIGGER ALL
and then run the contents of your trigger at then end or you can put your 3000 columns into a temp table and then insert them all at once. This will only setup 1 trigger. If this isn't enough please give us more info on what you are trying to do.
Your trigger will not fire 3000 times if you are modifying 3000 rows in a single statement. Your trigger will fire once and there will be 3000 rows in your virtual 'deleted' table.
If you are limited in how you can import the data into the system that does a single insert per row, I would suggest that you import data into an intermediate table then do the insert into the final table from the intermediate one.
There is a better way.
Re-link the tables that your trigger created or altered, compare them against what's expected to be changed or added and avoid the trigger with a simple WHERE clause.
eg - this trigger I use to INSERT a record, but only once based on a column value existing (#ack).
DECLARE #ack INT
SELECT #ack = (SELECT TOP 1 i.CUSTOM_BOOL_1 AS [agent_acknowledged] FROM inserted AS i)
IF #ack = 1
BEGIN
INSERT INTO TABLEA(
COLA, COLB, etc
)
SELECT
COLA, COLB, etc
from inserted as i
LEFT JOIN TABLEA AS chk --relink to the INSERT table to see if the record already exists
ON chk.COLA = i.COLA
AND chk.COLB = i.COLB
AND etc
WHERE chk.ID IS NULL --and here we say if NOT found, then continue to insert
END