The purpose of the trigger is exporting an specific data from a table with bcp after inserting data on that table, so I thought doing it in this way, I know that the trigger waits for bcp, that is waiting for a lock on the table to be released, but that lock is held until after the trigger, and for this reason it doesn't work. How can I do it? or do I need to add some function or something for that works?
I'm using SQL Server 2008.
ALTER TRIGGER [TRIGGER] on [TABLE] after INSERT AS BEGIN
DECLARE #CMD NVARCHAR(1000)
SET #CMD = 'cd.. && "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\bcp.exe" "SELECT TOP 1 CODE FROM[TABLE] WITH (NOLOCK) ORDER BY ID DESC" queryout "\\FOLDER\FOLDER\FILE.txt" -T -c -S "[SERVERNAME]"'
EXEC master..XP_CMDSHELL #CMD
END
Don't use bcp in a trigger. Even if you could get it to work it will slow down your database, probably to the point where it will not be usable. bcp is a command line utility and should be treated as one
I recommend that you use an SQL Server Agent to execute extra actions on a scheduled or triggered basis
You can also read this tutorial that will help you get started with Agents
If you do not have SQL Server Agent (Express does not include it), then you have a few other options:
Write your own Agent. Here is an example
Call a stored procedure after insert. This answer used that method to solve similar problem to the one you posted
Use a stored procedure to write data and process the export code
Use a scheduled task processes data on a schedule (this is where bcp can be used without killing server performance)
Not sure if this would work but you could try changing to an INSTEAD OF trigger and do the INSERT and bcp within the trigger
I suspect this may circumvent the lock on the table.
further reading - http://www.c-sharpcorner.com/UploadFile/37db1d/creating-and-managing-triggers-in-sql-server-20052008/
Related
How can I track the execution of source filename command in mysql so that I can have the filename and path of sql scripts that's been run. Google didn't help or may be I didn't use the right keyword.
So when I execute source ./test/file.sql (without errors preferably)
I want an entry in "source_history" table with current_time,filename(along with path) which I can do if I could figure how to track.
It'd be of great help if anyone could help me in keeping track of the command source.(Something like a trigger event for insert or update on table)
(may be, tracking all command in that sense and then while exiting mysql, get the query history and check for source)
Hope that makes sense.
Thanks in advance.
The problem is that the source command is not a MySQL command, it is a command in MySQL's command line interface, which is also named MySQL.
CLI only passes the sql commands within the file to the MySQL server, therefore the server cannot be aware of the exact file used for executing the command.
MySQL own documentation the source command (see the link above) suggests the most obvious solution:
Sometimes you may want your script to display progress information to
the user. For this you can insert statements like this:
SELECT '<info_to_display>' AS ' ';
So, the simples way is to create a table with fields for path, event type (start / stop) and a timestamp and add insert statements to the start and end of each sql file that log the start and the end of each batch and supply the name of the file hard coded in the insert statements. You may want to create a script that adds these commands to the sql files.
Alternative is to create a batch file that receives a path to an .sql file in a parameter, invokes MySQL's CLI, logs the start of the batch process in mysql, launches the .sql file, and then logs the completion of the batch in MySQL.
I am getting the following message while creating a stored procedure in MySQL Workbench:
"Review the SQL script to be applied on the database"
I have several tables inside the database but the stored procedure I am writing will be
used only for one table. Since, the SQL script of stored procedure is gonna apply on the whole database, I am wondering if it's gonna affect other tables as well? I don't want other tables to get disturbed because of this script.
Please provide your inputs as I am doing this for the first time.
Question #2:
Why do I see "DELIMITER $$" as the first statement while creating a routine before the following statement?
CREATE PROCEDURE `mydatabase`.`myfirstroutine` ()
BEGIN
Thanks
1) MySQL Workbench offers the option to review the generated SQL script before it is sent to the server. This way you can check it for possible problems.
2) The DELIMITER command is usually necessary to switch the current delimiter that ends a single statement (which is by default a semicolon) to something else because the stored procedure code itself needs the semicolon to separate individual commands. However the sp code must be sent as a whole to the server.
A few more details: the DELIMITER keywword is a client keyword only, that means the server doesn't know it and doesn't need it. It's an invention for clients to properly separate sql commands before sending them to the server (you cannot send a list of commands to a server, only individual statements).
In MySQL Workbench however, especially in the object editors where you edit e.g. the sp text, adding the DELIMITER command is essentially nonsense, because there's only this sp code, hence nothing to separate. This might disappear in future version but for now just ignore it.
For our system we are using multiple databases with the same structure. For example when we have 1000 customers, there will be 1000 databases. We've chosen to give each customers his own database, so we can delete all his data at once without any hassle.
Now I have to update the database structure several times a year. So I began to write a stored procedure which loops through all schemas. But I got stuck with executing a dynamic USE statement.
My code is as follows:
DECLARE V_SCHEMA VARCHAR(100);
SET V_SCHEMA = 'SomeSchemaName';
SET #QUERYSTRING = CONCAT('USE ', V_SCHEMA);
PREPARE S FROM #QUERYSTRING;
EXECUTE S;
DEALLOCATE PREPARE S;
When I execute this code I get an error which says Error Code: 1295. This command is not supported in the prepared statement protocol yet. So I assume that I cannot change the active database in a procedure.
I have searched the internet, but the only thing I found was creating a string of each alter query and prepare/execute/deallocate it. I hope there is a better solution for this. I could write a shell script that loops through the schemas and executes a SQL file on them, but I prefer a stored procedure that takes care of this.
Does anyone know how to make this work?
Thank you for your help!
EDIT: I use the latest stable version of MySQL 5.6
If there are some known databases, then try to write a CASE.
Otherwise, do not execute USE statement using prepared statements; instead, build other statements (SELECT, INSERT, UPDATE, ...) with full name - <database name> + '.' + <object name>, and execute them using prepared statements.
If you put your structure changes into a stored procedure in a temporary schema, you can do this within a Workbench SQL window.
You can build your iteration script using a query against the information_schema, e.g.
SELECT GROUP_CONCAT(CONCAT('USE ',schema_name,'; CALL tmp.Upgrade')
SEPARATOR ';\n') AS BldCode
FROM information_schema.schemata
WHERE schema_name NOT IN
('information_schema', 'performance_schema', 'mysql', 'sakila', 'world', 'tmp')
Since you cannot execute this as a prepared statement, you can copy the SQL result into a new SQL window, and run that.
Please note that the structure changes stored procedure would need to operate on the current schema, rather than specifying schemas.
I want to implement a batch MySQL script to do something in a database. The thing is that, for each master id that I have I want to insert 4 tuples. But this tuples should be added in a transaction which means if one of these 4 tuples is failed the transaction should be rollback. Then I need to have some catching mechanism to capture that the query is failed. I CAN ONLY USE PURE MYSQL neither PHP, nor PERL etc. Even I cannot create any store procedure to do that. In Microsoft SQL Server there is ##error variable that solved my problem but in MYSQL we do not have any system variables showing the error code.
how can I do that?
Cheers,
This is an ugly workaround, but it worked for me when I was trying to import a batch of SQL queries and wrap the entire thing within a transaction, so that I could roll back if any of the SQL queries errored.
Since the size of the batch was massive, a SQL procedure with condition handler was not an option either.
You have to do this manually, so it really isn't a solution unless you are batching:
First, make sure your entire batch is stored in an SQL file. The SQL file should only contain the batch queries, and no transaction control queries.
Then start up a MySQL command line client and type in transaction commands manually:
mysql> SET AUTOCOMMIT = 0;
mysql> START TRANSACTION;
Then tell the command line client to run the batch file:
mysql> SOURCE path/to/file.sql
After that you can simply manually COMMIT; or ROLLBACK; depending on how happy you are with the result of your queries.
This is such a kludge, though. Anyone have a better approach?
I am writing a stored procedure that needs to execute a .sql source file. The MySQL stored procedure must run the .sql script and provide a return value based on whether the .sql file exists, if an error occurs or if it exists and executes without errors. Can anyone provide me with some direction on the proper syntax to use in my stored procedure to call the .sql file? Is it simply CALL myfile.sql?
Thanks,
Sid
There are no commands in MySQL language to read a .sql file.
The "source" keyword is an internal command of the MySQL command line.
If you want to execute one SQL command from a file, you can do the following:
1) read the file into a table, using the LOAD DATA INFILE command (but some security restrictions apply);
2) load the first record from that file into a variable;
3) create a prepared statement from the variable;
4) execute the prepared statement.
The above procedure is fraught with restrictions and problems, however.
The first and most notable one is that allowing execution of generic code is a security liability. The second one is that you will have little control on what you are executing.
If you really must, you could use MySQL Proxy (http://launchpad.net/mysql-proxy), which can perform the above operations with much more control and flexibility on each step.