Microsoft SQL to MySQL trigger - mysql

I need help with converting MS SQL command for trigger creation to similar command in MySQL. It works fine in MS SQL but I know nothing of MySQL.
The command is as it follows:
USE [Project]
GO
/****** Object: Trigger [General].[TR_tblFirmaZaposleni_U] Script Date: 7.1.2014 17:47:35 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [General].[TR_tblFirmaZaposleni_U]
ON [General].[tblFirmaZaposleni]
FOR UPDATE
AS UPDATE [General].[tblFirmaZaposleni]
SET [A_tblFirmaZaposleniUpdatedBy] = SUBSTRING(SUSER_SNAME(),(CHARINDEX('\',SUSER_SNAME()) + 1),LEN(SUSER_SNAME())), [A_tblFirmaZaposleniUpdatedOn] = GetDate()
FROM [General].[tblFirmaZaposleni] s
INNER JOIN [INSERTED] i ON s.[ZaposleniID] = i.[ZaposleniID]
INSERT INTO ProjectAudit.[General].[tblFirmaZaposleni] SELECT 'B','U',* FROM DELETED
INSERT INTO ProjectAudit.[General].[tblFirmaZaposleni] SELECT 'A','U',* FROM INSERTED
GO

Despite their apparent similarities, SQL Server and MySQL are actually very different products: each of which deviate from the SQL standards in different ways. Indeed, the divergence significantly widens as one delves deeper into their features and functionality.
Thus there is not a 1:1 mapping between what you have in SQL Server and what can be done in MySQL. You would do well to read around on the differences between the systems and how migrations can best be managed. It may well be that significant elements of application design should be engineered specifically to take advantage (or overcome lacks) of features or functionality that exist in one system or the other.
To the extent that you do keep the databases similar, an equivalent set of commands in MySQL would look something like this:
USE Project
DELIMITER ;;
CREATE TRIGGER TR_tblFirmaZaposleni_U
BEFORE UPDATE ON tblFirmaZaposleni
FOR EACH ROW BEGIN
SET NEW.A_tblFirmaZaposleniUpdatedBy = SUBSTRING_INDEX(CURRENT_USER, '#', 1),
NEW.A_tblFirmaZaposleniUpdatedOn = CURRENT_DATE;
INSERT INTO ProjectAudit.tblFirmaZaposleni VALUES
('B','U', OLD.colA, OLD.colB, OLD.colC, ....),
('A','U', NEW.colA, NEW.colB, NEW.colC, ....);
END;;
It may be worth noting that, like SUSER_SNAME() in SQL Server, CURRENT_USER in MySQL returns the user as which the trigger is running, rather than the user as which the client was authenticated. You may wish to use MySQL's USER() function instead.
It may also be worth noting that MySQL offers Automatic Initialization and Updating for TIMESTAMP and DATETIME, which saves you having to set such values within a trigger.
As for the initial SET statements (which have no effect on the trigger), MySQL has no equivalent to SQL Server's ANSI_NULLS setting but you can set its ANSI_QUOTES SQL mode if you wish to achieve the same effect as setting SQL Server's QUOTED_IDENTIFIER.

Related

Syntax error in converting SQL Server trigger to MySQL

I have to convert SQLServer trigger to MySQL. I was trying to recreate it in MySQL but the thing is that I get syntax error every time I try different combinations and I don't know what's not working and why.
I'm creating cinema database and the following trigger is started when an entry is removed from the Hall table. Suppose a hall is being renovated and we have to move the performances in that hall to other locations. In this case, they are moved to a hall with an index 1 smaller than the distant hall.
Here is SQLServer query:
CREATE TRIGGER tDeleteHall ON Hall
FOR DELETE
AS
BEGIN
DECLARE #id int
SELECT #id = id_hall FROM deleted
UPDATE Spectacle set id_hall = #id - 1
END
DELETE FROM Hall WHERE id_hall = 3;
MySQL code
CREATE TRIGGER tDeleteHall BEFORE DELETE ON Hall
DECLARE #id int
SELECT #id = id_hall FROM deleted
UPDATE Spectacle set id_hall = #id - 1
END
DELETE FROM Spectacle WHERE id_hall = 3;
The error I'm getting:
ERROR: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE #id int
SELECT #id = id_sala FROM deleted
UPDATE Spectacle set id_hall = ' at line 2
It's not totally clear what this trigger is supposed to do. But here's a MySQL trigger that I think does the same thing.
CREATE TRIGGER tDeleteHall BEFORE DELETE ON Hall
FOR EACH ROW
BEGIN
UPDATE Spectacle SET id_hall = OLD.id_hall - 1;
END
MySQL does not have the deleted pseudo-table. Instead, it uses OLD.<column> to refer to the deleted row, or in INSERT and UPDATE triggers, use the NEW.<column> to refer to the new row version.
MySQL's triggers are always row triggers, not statement triggers as in SQL Server. Nevertheless, MySQL triggers require the FOR EACH ROW syntax. Perhaps someday they will also support statement triggers.
You don't need to DECLARE a local variable for the example you show. But if you do use a local variable, know that unlike SQL Server, local variables in MySQL routines must not use the # sigil.
MySQL has two types of variables:
Local variables, which do not use the # sigil. These are created with DECLARE, and assigned a data type. They are local to the code block they are declared in.
User-defined session variables, which do use the # sigil. You can use these inside triggers, but they are not local. In other words, the value you set will remain set in your session after the trigger is done. These variables are created when you set them, so you don't declare them with DECLARE. They don't have a data type.
Statements inside the code block must be terminated with ;. This creates an ambiguity because the CREATE TRIGGER statement itself needs to be terminated. But if you run this in a client that assumes that ; terminates the CREATE TRIGGER, and there are ; characters in the body of the trigger, it becomes confused. The solution is to use DELIMITER to change the terminator of the CREATE TRIGGER, then you can use ; inside the body. You should read https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html
On the other hand, if you execute CREATE TRIGGER using a query interface that only processes the input one statement at a time anyway, there's no ambiguity, so you don't need to change the DELIMITER. Examples would be most query APIs.
Stored routines in MySQL are quite different from SQL Server. You need to make an effort to read the documentation and study examples. It's not an efficient use of your time or ours to try to learn complex syntax via Stack Overflow.

Update\Insert data from grafana to mysql

Is is possible to update data or insert data from grafana to mysql. I have a requirement to insert/update information in mysql using a UI. Now I am already using grafana so wanted to know if there is any way we can use grafana to update or insert information
There is no input panel for taking user input and inserting that data to MySQL or any other. (Grafana v7.0)
For very minimalist input data you can use grafana variables as a hack.
Create example table for storing input in MySQL
CREATE TABLE `grafana_variable` (`variable` VARCHAR(64)) ENGINE = InnoDb;
In Grafana dashboard click settings icon:
then click:
add variable:
return to dashboard and you should see at the top:
create a new visualization panel or add another query in any already existing panel and add SQL query:
INSERT INTO `grafana_variable` VALUES ('${myvar}');
now every time you type into that field
and click away from it or use ie tab key the data will be inserted to the MySQL database.
mysql> select * from grafana_variable;
+---------------------+
| variable |
+---------------------+
| this is just a test |
+---------------------+
1 row in set (0.08 sec)
The downside of this hack is that the visualization tile will have in its upper left corner error icon:
with information (when you hover over it):
Found no column named time or time_sec
because the sql query of the visualization tile is inserting data instead of selecting it from database therefore there is no time or time_sec data.
Grafana also does not handle multiple MySQL statements so you cannot repair that by adding before or after the INSERT INTO ... statement second one with SELECT FROM. Maybe this could be somehow patched by using sub queries or something similar but I did not investigate that further.
Because the error as above can be due to multiple reasons not related to the hack it will be better to use the hack query in separate visualization tile - the one that you will remember (or even give descriptive panel tile) so you know that the error there is nothing unusual.
See grafana varialbes for more info about variables.
There is also useful list of already existing variables you can use same way as myvar I created. See section MACROS here For eg:
$__timeFrom()
and
$__timeTo()
have the start and the end of displayed time range.
Permissions and Security
The whole hack works because the MySQL user that grafana uses is allowed to execute INSERT statement, but if grafana is able to execute ANY statement then make sure that MySQL user that grafana uses is not allowed for example to execute statements like DROP ... or any other that is not related to INSERT data into the grafana_variable table as in example.
If you use MySQL as datasource for displaying data the grafana user should also be able to execute SELECT statements.
But nothing else than that.
Read about MySQL user premissions
Must hide Update as temporary table
I am working with postgres and Grafana. Probably it is quite similar.
With postgres you have to hide the update like this:
WITH UPDAT_TEMP AS (UPDATE MyTable SET MY_ROW='MY_TEXT' WHERE ID=99)
SELECT 1;
If you want to update various rows, you have to put various temporary tables.
The
Update my_table (rows) values(...)
does not work for me under Grafana.
Therefore:
WITH UPDAT_TEMP AS (UPDATE MyTable SET MY_ROW='MY_TEXT' WHERE ID=99),
WITH UPDAT_TEMP2 AS (UPDATE MyTable SET MY_ROW2='MY_TEXT2' WHERE ID=99)
SELECT 1;

What's wrong with my SQL Fiddle query?

Take a look at this simple query in SQL fiddle: http://sqlfiddle.com/#!2/c1eb6/1. This is a super-simple update query, why is it producing an error? I wonder if could it be a bug in that site?
Build Schema:
create table your_table (some_column varchar(50));
insert into your_table set some_column = '30# 11';
insert into your_table set some_column = '30# 12.00';
insert into your_table set some_column = '30# 13.5';
insert into your_table set some_column = 'abdfs';
insert into your_table set some_column = '0000000';
Query:
UPDATE your_table
SET some_column = 1;
A bit of background for those interested in some of the arcane issues I've been dealing with on SQL Fiddle:
Disable explicit commits in JDBC, detect them in SQL, or put the database in a readonly state (dba.se)
Essentially, I am trying to ensure that the fiddles always remain in a consistent state, even as people play with them. One thing I've worried about is people intentionally messing with the databases, breaking them for the other people that might be working with them (this has happened before, but not often fortunately).
I've found methods of keeping things clean for each of the database platforms, but interestingly each method is completely different for each platform. Unfortunately, for MySQL I had to resort to the worst option - only allowing SELECTs on the right-hand side. This is because there are too many ways to write queries that include implicit commits, and there is no way that I've found to prevent that from happening short of outright denial on the query side. This is quite unfortunate, I realize, but it seems to be required.
Anyhow, this particular bug was a result from a change I had recently made in the logic for MySQL. It is fixed now, and now reports the expected error message:
DDL and DML statements are not allowed in the query panel for MySQL;
only SELECT statements are allowed. Put DDL and DML in the schema
panel.
I got this error on SQL Fiddle because I was trying to use PostgresSql syntax, while the interpreter was set to MySql

SQL Server : track table inserts

I have a table which get new data inserted every minute or so. According to the source code I have here, it is only done in one class which is not used anymore.
Is there any way to trace the inserts? What I mean is to see which queries they were inserted by, who sent those queries etc. As much info as possible.
I have tried several ways myself (e.g.sp_who2 'Active' stored procedure) without any success. I also have access to the machine running the SQL server and to the transaction backup files (.trn files) but have no idea how to open those files.
Add trigger to the table which follows inserts and insert to other table these variables:
getdate(),
host_name(),
App_Name(),
suser_sname()
Seems to me that this is enough
The trigger looks like this:
CREATE TRIGGER YourTrigger On YourTable
AFTER INSERT
AS
SET NOCOUNT ON;
INSERT logtable
SELECT APP_NAME(), HOST_NAME(), SUSER_SNAME(), GETDATE(), * FROM INSERTED
GO
OR
you can use Sql Server Profiler for catching the queries - it may be more flexible
You may use sp_depends like this:
sp_depends tablename
This only states information in the same database but it might say what you need!

Can a VIEW in MySQL read from one table and store into another?

Does MySQL have anything like aufs? I want to use my production tables read-only and store changes into another table or database if possible.
Thank you!!
Does MySQL have anything like aufs?
No
Option1 - Use replication
You can put the (read-only) production database on one server and the change database on another server (can be on the same machine).
If you set the change database as a slave of the production database, all changes that happen (from some other source perhaps) will be replicated to your change database.
Changes in the change database will not be passed on to the production database.
The fact that the change database is not in sync with the production database may cause problems with the (one way) synchronization but you'd have to experiment with that.
See: http://dev.mysql.com/doc/refman/5.0/en/replication.html
Option 2 - dirty hack with triggers
You can put a trigger on your production table and have the trigger diverge the data to somewhere else.
warning this is a filthy hack and not recommend use of triggers at all.
DELIMITER $$
CREATE TRIGGER bu_prod_table1_each BEFORE UPDATE ON prod_table1 FOR EACH ROW
BEGIN
UPDATE change_table1 c SET c.field1 = NEW.field1, c.field2 = NEW.field2
WHERE c.id = OLD.id;
IF NEW.id <> OLD.id THEN
UPDATE change_table1 SET c.id = NEW.id WHERE c.id = OLD.id;
END IF;
/*reverse the changes in the production table*/
SET NEW.id = OLD.id;
SET NEW.field1 = OLD.field;
.....
END $$
DELIMITER ;
You'd have to create these triggers for UPDATE, DELETE, and INSERT.
And you'd have to put triggers on each and every table in production.
In other SQL implementations (e.g. SQL Server), an INSTEAD OF trigger on a VIEW can achieve the goal of reading from one table and writing to another. However, mySQL does not to my knowledge support INSTEAD OF triggers.