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
Related
I'm using SQLite 3.37.2 through Python 3.10.5, and editing the database with DBeaver - maybe it's not always at its best when reporting database errors.
Anyway, I want to convert a text (JSON) in SQLite proper JSON format upon insertion, by calling its json() function.
I thought about adding a simple trigger to handle that, but I can't figure out what's wrong in my syntax:
CREATE TRIGGER t1_before_insert AFTER INSERT ON t1 FOR EACH ROW
BEGIN
SET NEW.json:=json(NEW.json);
END
;
This is the latest version I attempted, I always get an error like
SQL error or missing database (near "SET": syntax error)
I tried:
SET NEW.json:=json(NEW.json)
SET NEW.json=json(NEW.json)
SELECT NEW.json:=json(NEW.json)
using an AFTER INSERT trigger
but none worked.
You can't change the value of a column of the new row like that.
You must update the table in an AFTER INSERT trigger:
CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 FOR EACH ROW
BEGIN
UPDATE t1
SET json = json(NEW.json)
WHERE t1.id = NEW.id;
END;
Change id to the table's primary key.
See the demo.
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.
Okay, so this is either not possible, or I suck at Googling. (the latter being the more likely here)
My question is this: Using stored procedures, is it possible to select a result set of ids into a variable, and then use those ids as the condition for an IN in an update that runs in the same SP?
I'm going for something like this (I recognize I'm ignoring delimiter conflicts here)
CREATE PROCEDURE test()
BEGIN
DECLARE var1 INT DEFAULT 0;
SELECT id INTO var1 FROM table WHERE this='this';
some other stuff
UPDATE table2 SET blah='blah' WHERE fk_id IN (var1);
END;
"some other stuff" basically manipulates data in such a way that I wont be able to get the appropriate list of ids by using an inner query inside the IN, so I basically need to "save" the appropriate list of ids into a variable and then use that variable later. Can this be done?
Please don't suggest other ways of doing this/restructuring my data/logic so I don't have to worry about this. All I need to know is if/how this can be done. I have backup options if it can't be done, this would just be the most preferable way.
Thanks in advance.
Something like this:
CREATE PROCEDURE test()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmp AS (SELECT id FROM table WHERE this='this');
some other stuff
UPDATE table2 SET blah='blah' WHERE fk_id IN (SELECT id FROM tmp);
END;
Is it possible to pass the NEW and the OLD tables from a trigger into a procedure in MySQL?
I suspect no, since there is no such a datatype as table that a procedure accepts.
Any workarounds possible?
Ideally it would look like this:
CREATE TRIGGER Product_log AFTER UPDATE ON Product
FOR EACH ROW BEGIN
call logChanges(OLD, NEW);
END;
You can explicitly pass each field:
CALL logChanges(OLD.colA, OLD.colB, NEW.colA, NEW.colB);
Or if logChanges must be sufficiently generic that it can handle such calls from different tables, one could concatenate the field values into a single string using a suitable delimiter (e.g. the unit separator):
CALL logChanges(CONCAT_WS(CHAR(31), OLD.colA, old.colB),
CONCAT_WS(CHAR(31), NEW.colA, NEW.colB));
Or if data types must be preserved, one could insert the records into a temporary from which logChanges reads.
it's not possible because there is no NEW or OLD table. The entire trigger is related to the table - the "new" and "old" refer to the rows and the values they contained before and after the event that was triggered. In other words, your example would be:
call logChanges(OLD.customername, NEW.customername)
You could also save all the OLD data in a history table (which I expect logchanges does anyways), basically being a clone of the production table something like this:
BEGIN
IF OLD.customer_name != NEW.customer_name
THEN
INSERT INTO myTable_chagne_history
(
customer_id ,
customer_name ,
another_field ,
edit_time
)
VALUES
(
OLD.customer_id,
OLD.customer_name,
OLD.another_field ,
NEW.time_edit_was_made
);
END IF;
END;
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.