I need to INSERT into table_2 values coming from a SELECT result set, if and only if a specific column exists in table_1, then that column has to be dropped from table_1. Else nothing should happen.
Is it all about DELIMITER?
As far as I know, no, since code isn't part of a procedure declaration. I tried it anyway but it did not seem to help. It is getting tricky for such a tiny task to run.
My code so far, which triggers syntax errors warnings from Workbench:
CASE
-- MysqlWorkbench complains (CASE is underlined) saying …
-- «Syntax error: 'CASE (case) is not valid input at this position'»
WHEN EXISTS (
SELECT * FROM information_schema.`COLUMNS`
WHERE `TABLE_SCHEMA` = 'bd_name'
AND `TABLE_NAME` = 'table_1'
AND `COLUMN_NAME` = 'name'
) THEN
INSERT INTO table_2 (caption,c_id)
SELECT DISTINCT label, c_id FROM bd_name.table_1;
ALTER TABLE table_1 DROP COLUMN label;
-- I'm not sure about how should I separate statements
-- regarding https://dev.mysql.com/doc/refman/5.7/en/case.html
END;
-- ("END" is underlined) Syntax error: extraneous input found - expected end of input
Thank you.
I don't think MySQL allows procedural constructs outside of routines, triggers, events, etc.... One way around this is to wrap your code in a proc declaration, and then follow it with a call to the proc and a drop of the proc.
Something like this:
DELIMITER $$
CREATE PROCEDURE foo()
BEGIN
Your stuff here;
and here;
END$$
DELIMITER ;
CALL foo();
DROP PROCEDURE foo();
Related
I'm trying out MySQL procedures for the first time, however I can't figure out how to define the variable #index_ids for the life of me. It really doesn't like the SET.
CREATE PROCEDURE #indextemp
BEGIN
SET #index_ids = (SELECT DISTINCT index_id FROM visibility_index_processing_queue WHERE process_id IS NOT NULL);
SELECT #index_ids;
END
Problem is in CREATE PROCEDURE syntax, not in setting variable. You just have to add parentheses after procedure name. Here's working sample
delimiter $
CREATE PROCEDURE indextemp()
BEGIN
SET #index_ids = (SELECT DISTINCT index_id FROM visibility_index_processing_queue WHERE process_id IS NOT NULL);
SELECT #index_ids;
END$
delimiter ;
Sometimes use of delimiter character in procedure body can cause problems too. That's why I set delimiter to $ before creating procedure and revert it to default ; after I'm done.
Also notice that I have removed # from your procedure name. In sql # is used to insert comments. If for some reason you really want to use it in your name you have to do it like that
CREATE PROCEDURE `#indextemp`()
CREATE TRIGGER `UpdateId`
BEFORE INSERT ON `comments`
FOR EACH ROW
set #vid=(select MAX(comments.id) from comments)+1;
set new.id=#vid;
this query gives me an error #1193 saying id variable is unknown.
Everybody that seemed to have a similar problem was not putting the 'new' clausole before the variable, but in my case it still doesn't work. The 'new' clausole doesn't get highlighted when I type it, it looks like it is not a special keyn word but a normal word instead.
From https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html, it looks like you might need to either use just one set statement or use a begin ... end construct. My hunch is that the create trigger statement ends at the first semi-colon, and then MySQL doesn't know what you're talking about when it gets to new.id=#vid;.
CREATE TRIGGER `UpdateId`
BEFORE INSERT ON `comments`
FOR EACH ROW
set
#vid=(select MAX(comments.id) from comments)+1,
new.id=#vid;
OR
delimiter //
CREATE TRIGGER `UpdateId`
BEFORE INSERT ON `comments`
FOR EACH ROW
begin
set #vid=(select MAX(comments.id) from comments)+1;
set new.id=#vid;
end;//
delimiter;
I am writing my first stored procedure as a trigger. I am doing this in a dev migration as we have two systems which don't speak to each other in dev, so I need to mock the data which would normally come from the other system.
My procedure is added as part of our dev migration script.
DELIMITER |;
CREATE TRIGGER `activity_insert` AFTER INSERT ON `activity`
FOR EACH ROW
BEGIN
UPDATE `activity` AS `a` JOIN `handle` AS `h` on `a.handle_id` = `h.handle_id` SET `path` = CONCAT(`h.handle`,'/',`a.activity_handle`) WHERE `a.path` IS NULL;
END;
|
DELIMITER;
I would expect the logic to be:
DELIMITER $$
CREATE TRIGGER activity_insert BEFORE INSERT ON activity
FOR EACH ROW
BEGIN
IF new.path IS NULL THEN
SET new.path = (SELECT CONCAT(h.handle, '/', new.activity_handle)
FROM handle h
WHERE new.handle_id = h.handle_id
);
END IF;
END;$$
DELIMITER;
There are numerous problem with your code:
You don't update the table being modified using update.
You want a "before" triggers, not an "after trigger".
Don't use | for the the delimited. It is a valid MySQL operator.
You have over-used the backtick, including putting the table alias in with the column alias.
This assumes that handle.handle_id is unique. This seems like a reasonable assumption based on the names, but you can add limit 1 to guarantee no more than one row is returned.
Working only with MySQL (I have essentially no PHP knowledge), I need to have a table that's essentially a subset from a much larger table. The source table changes from time to time, losing some entries, gaining other new ones, and values changing for existing ones. I can describe what I want to happen, but can't seem to figure out a syntax of commands to make it work. I also know I can have two separate queries and just run whichever one I need, and I have that worked out, but I'd like to combine them if possible. Here's what I want:
IF the subset_table DOES NOT EXIST, create it as [select query], ELSE truncate the subset_table and insert [select query]
Like I said, I know there are other ways to do this - I could drop if exists/create, or I could just have two different sql files to run. I just want to know if I can do this as specified above.
Thoughts?
You can do this:
create table if not exists <tablename> . . .;
truncate table <tablename>;
insert into <tablename>(cols)
select blah blahblah . . .;
You don't need any if statements at all.
This can also be done through an SP (stored procedure)... makes it more readable and safe
DELIMITER $$
DROP PROCEDURE IF EXISTS `create_table_sp`$$
CREATE PROCEDURE `create_table_sp`()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.TABLES WHERE table_name = '<table_name>'
AND table_schema = DATABASE() AND table_type = 'BASE TABLE') THEN
CREATE TABLE <subset_table_name>
AS SELECT * FROM <main_table_name>;
ELSE
TRUNCATE TABLE <subset_table_name>;
INSERT INTO <subset_table_name>
AS SELECT * FROM <main_table_name>;
END IF;
END$$
DELIMITER ;
CALL `create_table_sp`;
DROP PROCEDURE IF EXISTS `create_table_sp`;
There is also another way,
You could pass the table names as arguments to the SP, in this case sub_table_name and main_table_name
Make the above DML statements to a string using CONCAT()
Create a prepared statement out of it and execute
Hope this helped....
I'm trying to select a column from a record variable in a function I'm calling from an Update rule and am getting the following error:
'could not identify column "name" in record data type'
The following is what I'm doing to produce the error:
From within an Update rule:
SELECT * INTO TEMPORARY TABLE TempTable FROM NEW;
SELECT MyFunction();
From within MyFunction()
DECLARE RecordVar Record;
SELECT * INTO STRICT RecordVar FROM TempTable;
EXECUTE 'UPDATE AnotherTable SET column = $1.name' USING RecordVar;
Note: I realise that there are easier ways to achieve what the above code is achieving but I've simplified the actual implementation to focus on the problem I'm having, which has opened up other possible solutions but I'd really like to get the above code working if possible.
I just figured it out. Rather than inserting the columns from NEW into the Temporary Table, I insert the NEW record as a single column into the Temporary Table and refer to it as RecordVar."NEW" inside my function. My rule and function now look like this:
From within an Update rule:
SELECT NEW AS "NEW" INTO TEMPORARY TABLE TempTable;
SELECT MyFuction();
From within MyFunction()
DECLARE RecordVar Record;
SELECT * INTO STRICT RecordVar FROM TempTable;
EXECUTE 'UPDATE AnotherTable SET column = $1.name' USING RecordVar."NEW";
The second part could work like this:
DO
$BODY$
DECLARE
RecordVar TempTable;
BEGIN
SELECT * INTO STRICT RecordVar FROM TempTable LIMIT 1;
EXECUTE 'UPDATE AnotherTable SET column = $1.name'
USING RecordVar;
END;
$BODY$
Note how I use the table name as type. PostgreSQL automatically creates a composite type for every table in the system.
A variable holds one row, the SELECT can return many rows. All but the first will be discarded. I added LIMIT 1 to clarify the effect. I doubt that is what you want.
You probably shouldn't have to use a temporary table in a rule to begin with. You may want to post your complete setup ...