So I have this trigger that I wrote for a MySQL environment, and which I now need to transfer to a SQL Server environment.
Being unfamiliar with Transact SQL, I have a little trouble translating from one to the other or creating an equivalent. Here is the simplified query:
CREATE TRIGGER <myTrigger> BEFORE INSERT ON <myTable>
IF NEW.<myColumnContainingBoolean> = TRUE THEN
SET NEW.<myColumnReferenceCode> = CONCAT(YEAR(NOW()),MONTH(NOW()),DAY(NOW()), 'indice');
ENDIF;
The goal is to add a reference number (today's date writted yyyymmdd + 'indice') according to the value of a boolean contained in the query, to summarize, if, at the time of the INSERT, the value of the boolean is on TRUE then we insert the code on this same line, otherwise we don't write a reference. Here is a maybe more explicit example :
Example
I have sincerely tried a lot of things, what seems to come closest to my request is this one (which, of course, does not work):
CREATE TRIGGER <myTrigger>
ON <myTable>
AFTER INSERT
AS
BEGIN
IF <myColumnContainingBoolean>
SET <myColumnReferenceCode> = CONCAT(YEAR(GETDATE()),MONTH(GETDATE()),DAY(GETDATE()), 'indice');
FROM inserted
END
GO
Ok, I guess we have to use a trigger (immense sigh).
Here's how you would do it in SQL Server:
CREATE TRIGGER <your schema>.<your table>_Insert ON <your schema>.<your table>
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO <your schema>.<your table> (<your other columns>,<myColumnReferenceCode>)
SELECT
<your other columns>
,CASE
WHEN <myColumnContainingBoolean> = 1 THEN FORMAT(GETDATE(),'yyyyMMdd') + 'indice'
ELSE <myColumnReferenceCode>
END
FROM
inserted
END
GO
If you're using an auto-incremented (IDENTITY) column, make sure to leave it off your insert list inside the trigger.
Other observations: You could probably just make <myColumnReferenceCode> a date and store GETDATE() and get the same functionality, but I don't know all of your circumstances.
Related
Hello i am tring to take a log of the column name old value and new value that is being modified.I went through the solution available but getting the errors of sql syntax. Unsure where issue actually lies.
Trigger i genrated in as below
CREATE TRIGGER `products_change` AFTER UPDATE ON `products`
FOR EACH ROW in
BEGIN
IF NEW.name <> OLD.name THEN
INSERT INTO product_change_logs(column_name, old_value, new_value) values ('name', OLD.name ,NEW.name);
END IF;
END
Also tried information schema to loop through the column name to avoid the if else but facing the same. Request to please guide with a best approach to create the same, also way to pass the value to trigger like user_id or something.
Any help is deeply appreciated.
create trigger cal_retweet before insert on T
for each row begin
set NEW.retweet_change = NEW.retweet_count - retweet_count where id_str = NEW.id_str
end
SQL said there is syntax error near "where id_str = NEW.id_str"
My table looks like this. Where id_str is a unique identifier for a specific tweet. Since I am inserting 50 tweets from a single user every minute, there would be many same id_str. What I want to look at is the change of retweet_count every minute. tweeted_at is when the user tweeted, created_at is when this data is inserted into my database. I want to generate retweet_change for each new data inserted into the database compared to the same old tweet (into the column retweet_change). How should I write the trigger?
After reading some of your comments I changed my code to :
create trigger cal_retweet before update on T
for each row
begin
set NEW.retweet_change = NEW.retweet_count - OLD.retweet_count;
end;
There is still syntax error
There are several issues with this trigger.
You have some syntax errors. You need proper semicolons to delimit your statements.
You have a WHERE statement that is out of place (and actually not needed). You are acting on only a single row at a time, you don't have to match on the id_str.
In order to factor in a calculation using an existing value from the row, you need access to the OLD keyword. For that, you need a trigger that happens on UPDATE, not INSERT. On INSERT, the retweet_change is simply the same as retweet_count; you could alter your INSERT statement to fix that problem.
You may need to explicitly add a statement delimiter as per the comments below.
So all together, I think this trigger should look like:
DELIMITER //
CREATE TRIGGER cal_retweet BEFORE UPDATE ON T
FOR EACH ROW
BEGIN
SET NEW.retweet_change = NEW.retweet_count - OLD.retweet_count;
END;//
DELIMITER ;
Is it possible to create a trigger that outputs a CSV file selecting Fields 1 from Table 1 right after Table 2 is updated?
I have tried using
CREATE OR ALTER trigger test_a0 for Table 2
active after insert or update position 0
AS
begin
if (updating and new.field1 is not null) then
output ('C:\test\test.csv');
select field1 from table1;
output;
commit;
end
No, this it is not possible to output to a CSV file in triggers in Firebird 2.5. If you want to output to a file, you either need to do that in a client application, or use an external table (which technically is a binary format, not a text format). It might be possible to create a convoluted solution using UDFs.
In Firebird 3, a simpler solution might be possible using a UDR (User Defined Routines), but this is largely unknown territory, so I'm not actually sure if it can be done that way.
I suppose you can do it with IBExpert tools ibeblock
execute ibeblock
as
begin
txt='';
for
select firstname, lastname
from customer
into :fn,:ln
do
begin
txt=txt+fn+';'+ln+ibec_crlf();
end;
ibec_SaveToFile('C:\txt.csv',txt,__stfOverwrite);
end
I have a trigger containing this:
SET v1 = CONCAT_WS(',',NEW.ID, NEW.Name, NEW.Type, NEW.Value);
Can this be simplified into something like this to include the entire new row?:
SET v1 = CONCAT_WS(',',NEW.*);
(I've tried variations of the above however they causes syntax errors)
Thanks
No, there's no easy way to do this. You have to reference each column.
The only real workaround is to use the table metadata to help you generate the statement you want, and then include that statement in your procedure.
You wouldn't want to do this dynamically in the TRIGGER, even if it were possible.
SELECT CONCAT('NEW.`',GROUP_CONCAT(c.column_name
ORDER BY ORDINAL_POSITION SEPARATOR '`,NEW.`'),'`')
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'mytable'
That should get you a string that looks like:
NEW.`ID`,NEW.`Name`,NEW.`Type`,NEW.`Value`
And you can paste that into your trigger body. (Of course you could extend the CONCAT to generate the whole line.)
The downside is that when new columns are added to the table, those won't get automatically included; that will require a change in the trigger. If a column gets dropped or renamed, your trigger will start throwing exceptions; again requiring a fix to the trigger.
UPDATE
Q:How can I convert this string into a MySQL query?
#query = "CONCAT_WS(',','CCC','64',NEW.Record,NEW.ID,NEW.Name,NEW.User_ID,NEW.State_Record,NEW.Hash);"
I wouldn't convert that to a query. I would just use that as static line of code (with no double quotes) in the body of your trigger, just like the original statement you had in your TRIGGER.
SET v1 = CONCAT_WS(',','CCC','64',NEW.Record,NEW.ID,NEW.Name,NEW.User_ID,NEW.State_Record,NEW.Hash);
(It wasn't clear what you intended to do with that string.)
If you are trying to create a SELECT statement, you could try removing that semicolon from the end of the string, and prepending a SELECT keyword on it. But I don't think the NEW. references to the column values of the current row will be recognized in that context. That might happen, but you'd need to test.
If I needed to do something like that, I would do it using user variables,
SET #new_id = NEW.ID;
SET #new_name = NEW.Name;
SELECT #new_id, #new_name
It's not at all clear to me what you are going to do with the result set returned by a query like. If you are attempting to audit changes to the table, the normative pattern is to run an INSERT of the column values into an changelog table,
INSERT INTO mytable_changelog (ID, Name) VALUES (NEW.ID, NEW.Name);
It really depends on what you are trying to accomplish.
In a sql script that does sequential execution, is there a way one can introduce an IF THEN ELSE conditional to control the flow of query execution?
I happened to run into this http://www.bennadel.com/blog/1340-MySQL-Does-Not-Support-IF-ELSE-Statements-In-General-SQL-Work-Flow.htm
which says that the IF THEN ELSE will not work in a sql script.
Is there another way around?
Basically, I want to run a particular "select colName from table" command and check if colName corresponds to a particular value. If it does, proceed with the rest of the script. Else, halt execution.
Please advise.
I just wrap my SQL script in a procedure, where conditional code is allowed. If you'd rather not leave the statements lying around, you can drop the procedure when you're done. Here's an example:
delimiter //
create procedure insert_games()
begin
set #platform_id := (select id from platform where name = 'Nintendo DS');
-- Only insert rows if the platform was found
if #platform_id is not null then
insert into game(name, platform_id) values('New Super Mario Bros', #platform_id);
insert into game(name, platform_id) values('Mario Kart DS', #platform_id);
end if;
end;
//
delimiter ;
-- Execute the procedure
call insert_games();
-- Drop the procedure
drop procedure insert_games;
If you haven't used procedures, the "delimiter" keyword might need some explanation. The first line switches the delimiter to "//" so that we can include semi-colons in our procedure definition without MySQL attempting to interpret them yet. Once the procedure has been created, we switch the delimiter back to ";" so we can execute statements as usual.
After doing some research I think I may have found a way to work around this. I was looking for a way to verify if a script had already executed against a target database. This will be primarily for version control of my databases. I have a table created to keep track of the scripts that have been executed and wanted some flow inside my scripts to check that table first before execution. While I have not completely solved the problem yet I have created a simple script that basically does what I need, I just need to wrap the DDL into the selects based on the value of the variables.
step 1 - Setup a bit variable to hold the result
step 2 - do your select and set the variable if the result is found
step 3 - Do what you need to do on false result
step 4 - Do what you need to do on true result
Here is the example script
set #schemachangeid = 0;
select #schemachangeid := 1 from SchemaChangeLog where scriptname = '1_create_tables.sql';
select 'scriptalreadyran' from dual where #schemachangeid = 1;
select 'scriptnotran' from dual where #schemachangeid = 0;
I also recognize this is an old thread but maybe this will help someone out there trying to do this kind of thing outside of a stored procedure like me.