I have these two tables:
create table possiede (
soc1 integer not null,
soc2 integer not null,
primary key (soc1,soc2),
perc double
);
create table contr (
soc1 integer not null,
soc2 integer not null,
primary key(soc1, soc2)
);
I have these two triggers in a generic SQL syntax and I need to translate them into MySQL syntax:
create trigger contrDir
after insert on possiede
for each row
when percent > 0.5 and (soc1,soc2) not in (select * from contr)
insert into contr values (soc1,soc2);
create trigger contrIndir
after insert on possiede
referencing new table as newTable
for each row
insert into possiede values
(select P.soc1, N.soc2, P.perc+N.perc
from newTable as N join possiede as P on N.soc1 = P.soc2);
this was my first try, but it gives me an error on "referencing" keyword ("syntax error, unexpected IDENT_QUOTED, expecting FOR_SYM") and I'm not sure the translation is correct:
create trigger controllo
after insert on possiede
REFERENCING new table as newTable
for each row
begin
insert into possiede (select P.soc1, N.soc2, P.perc+N.perc from
newTable as N join possiede as P on N.soc1=P.soc2);
if percent > 0.5 and (soc1,soc2) not in (select * from contr) then
insert into contr values (soc1,soc2);
end if;
end;
also as you noticed I had to compress two triggers into one because of some MySQL constraints. Could somebody give me the right translation?
Please put the column names inside the braces and use NEW_TABLE. In addition, I think the IN CLAUSE within IF BLOCK is incorrect as you are checking two columns(soc1 and soc2) against select * from.... Please try using the updated query as below:
CREATE TRIGGER controllo
AFTER INSERT on possiede
REFERENCING NEW_TABLE AS newTable
FOR EACH ROW
BEGIN
INSERT INTO possiede (soc1, soc2, perc)
SELECT P.soc1, N.soc2, P.perc+N.perc
FROM newTable AS N JOIN possiede AS P ON N.soc1=P.soc2;
IF percent > 0.5 and soc1 not in (select soc1 from contr)
and soc2 not in (select soc2 from contr)
THEN
INSERT INTO contr VALUES (soc1,soc2);
END IF;
END;
Related
I have a lot of different tables in my database, and I need somehow to get last inserted rows from those tables. Like social networks feeds. Also, those tables are have not random, but unknown names, because they all generated by users.
In example:
I have tables: A,B,C and D with 5k rows in each table.
I need somehow to get last rows from those tables and make it ordered by id, like we do in a simple query: "SELECT * FROM table A ORDER BY id DESC", but I'm looking for something like: "SELECT * FROM A,B,C,D ORDER BY id DESC".
Tables have same structure.
You can use union and order by if your tables have the same structure. Something like:
select *
from (
select * from A
union all
select * from B
union all
select * from C
) order by id desc
If the tables don't have the same structure then you cannot select * from all and order them and you might want to do two queries. First would be:
select id, tableName
from (
select id, 'tableA' as tableName from A
union all
select id, 'tableB' as tableName from B
union all
select id, 'tableC' as tableName from C
) order by id desc
Which will give you the last IDs and the tables where they are inserted. And then you need to get the rows from each respective table.
With pure Mysql it will be a bit hard. You can select the table names like:
SELECT table_name FROM information_schema.tables; but still how to use them in the statement? You will need to generate it dynamically
A procedure to generate the query dynamically can be something like ( I haven't tested it but I believe with some debugging it should work) :
DELIMITER $$
CREATE PROCEDURE buildQuery (OUT v_query VARCHAR)
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_table_count INTEGER DEFAULT 0;
DECLARE v_table varchar(100) DEFAULT "";
-- declare cursor for tables (this is for all tables but can be changed)
DEClARE table_cursor CURSOR FOR
SELECT table_name FROM information_schema.tables;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN table_cursor;
SET v_query="select * from ( ";
get_table: LOOP
FETCH table_cursor INTO v_table;
SET v_table_count = v_table_count + 1;
IF v_finished = 1 THEN
LEAVE get_table;
END IF;
if v_table_count>1 THEN
CONCAT(vquery, " UNION ALL ")
END IF;
SET v_query = CONCAT(vquery," select * from ", v_table );
END LOOP get_table;
SET v_query = CONCAT(vquery," ) order by id desc " );
-- here v_query should be the created query with UNION_ALL
CLOSE table_cursor;
SELECT #v_query;
END$$
DELIMITER ;
If each table's id is counted seperatly you can't order by ID, so you'll need to calculate a global id and use it on all of your tables.
You can do it as follows:
Assuming you have 2 tables A,B:
Create Table A(id int NOT NULL auto_increment, name varchar(max), value varchar(max), PRIMARY_KEY(id));
Create Table B(id int NOT NULL auto_increment, name varchar(max), value varchar(max), PRIMARY_KEY(id));
Add another table IDS with id as auto increment primary key.
Create table IDS (id int NOT NULL auto_increment, ts Timestamp default CURRENT_TIMESTAMP, PRIMARY_KEY(id));
For all your tables id column should use now the id from the IDS table as foreign key instead of auto increment.
Create Table A(id int NOT NULL auto_increment, name varchar(max), value varchar(max), PRIMARY_KEY(id),CONSTRAINT fk_A_id FOREIGN KEY(id) REFERENCE IDS(id) ON DELETE CASCADE ON UPDATE CASCADE);
Create Table B(id int NOT NULL auto_increment, name varchar(max), value varchar(max), PRIMARY_KEY(id),CONSTRAINT fk_A_id FOREIGN KEY(id) REFERENCE IDS(id) ON DELETE CASCADE ON UPDATE CASCADE);
for each table add before insert trigger, the trigger should first insert row to the IDS table and insert the LAST_INSERT_ID the table.
Create TRIGGER befor_insert_A BEFORE INSERT On A
FOR EACH ROW
BEGIN
insert into IDS() values ();
set new.id = LAST_INSERT_ID();
END
Create TRIGGER befor_insert_B BEFORE INSERT On B
FOR EACH ROW
BEGIN
insert into IDS() values ();
set new.id = LAST_INSERT_ID();
END
Now you can create view from all tables with union all, the rows of v can be sorted now by the id and give the cronlogic order of insertion.
Create view V AS select * from A UNION ALL select * from B
For example you can query on V the latest 10 ids:
select * from V Order by id desc LIMIT 10
Other option is to add timestamp for each table and sort the view by the timestamp.
Hi are you looking for this? However the id is not a good column to see the last updated among different tables.
select *
from A
join B
on 1=1
join C
on 1=1
join D
on 1=1
order by A.id desc
I want to write a trigger in MySQL which copy table1’s column1 to table2’s column1
But table2’s column1 must to be unique, table1’s column1 is duplicable.
Any one suggest me how to conditionally sync up between this 2 tables using triggers.
You could improve your question by stating what kind of trigger you want (insert,update,delete) and what you want to happen if a duplicate is found. Assuming you want an insert trigger and table2.id has unique key you could use insert ignore to ignore the error and throw away the the attempted insert from table1 , you could use insert..on duplicate key to update table2. If table2.id does not have a unique key you could code to find if the key would be duplicated and then apply the insert option you prefer. I have assumed that you don't simply want to throw an error if a duplicate is encountered. Here's some sample code and data for you.
DROP TABLE IF EXISTS TABLE1,TABLE2;
CREATE TABLE TABLE1(ID INT, VALUE INT);
CREATE TABLE TABLE2(ID INT PRIMARY KEY, VALUE INT);
DROP TRIGGER IF EXISTS T;
DELIMITER $$
CREATE TRIGGER T AFTER INSERT ON TABLE1
FOR EACH ROW
BEGIN
INSERT IGNORE INTO TABLE2 VALUES (NEW.ID,NEW.VALUE);
END $$
INSERT INTO TABLE1 VALUES(1,1);
SELECT * FROM TABLE2;
INSERT INTO TABLE1 VALUES(1,2);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
DROP TRIGGER IF EXISTS T;
DELIMITER $$
CREATE TRIGGER T AFTER INSERT ON TABLE1
FOR EACH ROW
BEGIN
INSERT INTO TABLE2 VALUES (NEW.ID,NEW.VALUE)
ON DUPLICATE KEY UPDATE VALUE = NEW.VALUE;
END $$
DELIMITER ;
SELECT * FROM TABLE2;
INSERT INTO TABLE1 VALUES(1,3);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
DROP TRIGGER IF EXISTS T;
DELIMITER $$
CREATE TRIGGER T AFTER INSERT ON TABLE1
FOR EACH ROW
BEGIN
DECLARE FOUND INT DEFAULT 0;
SELECT 1 INTO FOUND FROM DUAL WHERE EXISTS(SELECT ID FROM TABLE2 WHERE ID = NEW.ID);
IF FOUND = 0 THEN
INSERT INTO TABLE2 VALUES (NEW.ID,NEW.VALUE);
ELSE
INSERT INTO TABLE2 VALUES (NEW.ID,NEW.VALUE)
ON DUPLICATE KEY UPDATE VALUE = NEW.VALUE;
END IF;
END $$
DELIMITER ;
SELECT * FROM TABLE2;
INSERT INTO TABLE1 VALUES(1,4),(2,1);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
This is how my table looks like and i want to now add a new row at the top with serialNo. "1" :
Existing table table1 has autoincrement column id and create a temp table with same table structure and insert the value you want to insert at top and then insert all record from existing table table1
then drop table1 and rename temp table temp01 to table1
SELECT TOP 1000 [id]
,[name]
,[age]
FROM [Mydb].[dbo].[table1]
CREATE TABLE temp01 (
ID int NOT NULL IDENTITY(1,1)PRIMARY KEY,
[name] varchar(255) NOT NULL,
Age int
);
INSERT INTO temp01 values('d',40)
INSERT INTO temp01 (name,age) SELECT name,age FROM table1;
drop table table1
exec sp_rename 'temp01', 'table1'
First you need to increment all the rows' serial numbers by one to make room for the new row:
UPDATE noticepdf
SET `serialNo.` = `serialNo.` + 1
ORDER BY `serialNo.` DESC;
The ORDER BY is so that the rows are updated from bottom to top; otherwise the top row will be incremented from 1 to 2, which will fail because there is already a row with 2.
Now you can just insert the row, specifying the serial number as 1:
INSERT INTO noticepdf (`serialNo.`, ...) VALUES (1, ...);
Where ... is replaced with your other fields.
The above can be wrapped up in a stored procedure as so:
DELIMITER $$
CREATE PROCEDURE insert_noticepdf (noticeNumber TEXT, pdf BLOB)
BEGIN
UPDATE noticepdf
SET `serialNo.` = `serialNo.` + 1
ORDER BY `serialNo.` DESC;
INSERT INTO noticepdf (`serialNo.`, noticeNumber, pdf)
VALUES (1, noticeNumber, pdf);
END$$
DELIMITER ;
I am using this code to insert a default row if the table is definitely empty. I am trying to extend this to insert multiple rows but cannot figure out the syntax:
INSERT INTO myTable(`myCol`)
SELECT 'myVal'
FROM DUAL
WHERE NOT EXISTS (SELECT * FROM myTable);
What i am getting (#Uueerdo)
CREATE TEMPORARY TABLE `myDefaults` ( name VARCHAR(100) NULL DEFAULT NULL);# MySQL returned an empty result set (i.e. zero rows).
INSERT INTO myDefaults (name) VALUES ('a'), ('b');# 2 rows affected.
SET #valCount := 0;# MySQL returned an empty result set (i.e. zero rows).
SELECT COUNT(1) INTO #valCount FROM blsf;# 1 row affected.
INSERT INTO blsf(name)
SELECT name
FROM myDefaults
WHERE #valCount > 0;# MySQL returned an empty result set (i.e. zero rows).
DROP TEMPORARY TABLE `myDefaults`;# MySQL returned an empty result set (i.e. zero rows).
Something like this should work:
CREATE TEMPORARY TABLE `myDefaults` ( the_value INT|VARCHAR|whatever... )
;
INSERT INTO myDefaults (the_value) VALUES (myVal1), (myVal2), ....
;
SET #valCount := 0; -- Because I am paranoid ;)
SELECT COUNT(1) INTO #valCount FROM myTable;
INSERT INTO myTable(myCol)
SELECT the_value
FROM myDefaults
WHERE #valCount = 0
;
DROP TEMPORARY TABLE `myDefaults`;
http://sqlfiddle.com/#!2/ba9ed/1
INSERT INTO table1 (myColumn)
SELECT
'myValue'
FROM (
SELECT COUNT(*) c
FROM table1 t
HAVING c=0) t2;
Hoping someone can help me with a mysql query
Here’s what I have:
I table with a column “networkname” that contains data like this:
“VLAN-338-Network1-A,VLAN-364-Network2-A,VLAN-988-Network3-A,VLAN-1051-Network4-A”
I need a MySQL query that will update that column with only the vlan numbers in ascending order, stripping out everything else. ie.
“338, 364, 988, 1051”
Thanks,
David
In this script, I create a procedure to loop through the networkname values and parse out the numbers to a separate table, and then update YourTable using a group_concat function. This assumes your networkname values follow the 'VLAN-XXX' pattern in your example where 'XXX' is the 3-4 digit number you want to extract. This also assumes each record has a unique ID.
CREATE PROCEDURE networkname_parser()
BEGIN
-- load test data
drop table if exists YourTable;
create table YourTable
(
ID int not null auto_increment,
networkname nvarchar(100),
primary key (ID)
);
insert into YourTable(networkname) values
('VLAN-338-Network1-A,VLAN-364-Network2-A,VLAN-988-Network3-A,VLAN-1051-Network4-A'),
('VLAN-231-Network1-A,VLAN-4567-Network2-A'),
('VLAN-9876-Network1-A,VLAN-321-Network2-A,VLAN-1678-Network3-A');
-- add commas to the end of networkname for parsing
update YourTable set networkname = concat(networkname,',');
-- parse networkname into related table
drop table if exists ParseYourString;
create table ParseYourString(ID int,NetworkNumbers int);
while (select count(*) from YourTable where networkname like 'VLAN-%') > 0
do
insert into ParseYourString
select ID,replace(substr(networkname,6,4),'-','')
from YourTable
where networkname like 'VLAN-%';
update YourTable
set networkname = right(networkname,char_length(networkname)-instr(networkname,','))
where networkname like 'VLAN-%';
end while;
-- update YourTable.networkname with NetworkNumbers
update YourTable t
inner join (select ID,group_concat(networknumbers order by networknumbers asc) as networknumbers
from ParseYourString
group by ID) n
on n.ID = t.ID
set t.networkname = n.networknumbers;
END//
Call to procedure and select the results:
call networkname_parser();
select * from YourTable;
SQL Fiddle: http://www.sqlfiddle.com/#!2/01c77/1