MariaDB : Trigger keeps getting syntax error after insert - mariadb

I have two tables. Table vitamin contains column vitamin_name and price. Table vitamin_variety contains columns price_variety and price_variety_extreme. I want to create an AFTER INSERT Trigger, that will insert the price of vitamin if the value of vitamin_name contains extreme into price_variety_extreme and not contains extreme into price_variety .
Here's what I mean if I insert this into vitamin, the price will be input into vitamin_variety
table = vitamin
+----------------+-------+
| vitamin_name | price |
+----------------+-------+
| extreme pill 1 | 10 |
| pill 1 | 5 |
| extreme pill 2 | 20 |
| pill 2 | 10 |
+----------------+-------+
table = vitamin_variety
+---------------+-----------------------+
| price_variety | price_variety_extreme |
+---------------+-----------------------+
| 5 | 10 |
| 10 | 20 |
+---------------+-----------------------+
my query keeps getting syntax error. it keeps saying
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use
near '' at line 5
what's wrong?
create trigger vitamin_ain after insert on vitamin
for each ROW
if vitamin.vitamin_name like 'extreme%' then
update vitamin_variety
set price_variety_extreme = new.price_variety_extreme;
else if vitamin.vitamin_name not like 'extreme%' then
update vitamin_variety
set price_variety = new.price_variety;
end if;

There are some syntax issues, and other situations, but the conditions inside the trigger could look like the code below:
First, (not right or wrong) the else if could be simplified to an else. If the first condition finds extreme, there is no need to inverse check for not like extreme. (unless some strange requirement expects that handling)
Of course, feel free to keep the else if check as-is, if it makes more sense to you, but I used this code:
if new.vitamin_name like 'extreme%' then
update vitamin_variety
set price_variety_extreme = new.price;
else
update vitamin_variety
set price_variety = new.price;
end if
The 'syntax issues':
In the if condition, change vitamin.vitamin_name to new.vitamin. Columns from trigger insert actions are referenced from new, not the table name.
If keeping your original else if, need to change the same vitamin.vitamin_name reference mentioned in item 1.
References new.price_variety_extreme and new.price_variety do not exist from the vitamin insert (these columns are not in vitamin), but new.price is, and the other vitamin columns.
The 'other situations':
Without any rows already present in the vitamin_variety table, no update will occur, because there are not any rows to update. This situation will make it seem as if the trigger is not working, but there is nothing for the trigger to update.
The desired output to vitamin_variety cannot be achieved with the current info. The update will set ALL columns of one or the other to the last inserted price, because there is no unique row reference. (no WHERE clause to limit what row(s) get updated)
Here's some sample interaction:
As the first other situation mentioned, there are no rows in the vitamin_variety table, so I added one:
MariaDB [test]> insert into vitamin_variety (price_variety, price_variety_extreme) values (0, 0);
Query OK, 1 row affected (0.08 sec)
MariaDB [test]> select * from vitamin_variety;
+----+---------------+-----------------------+
| id | price_variety | price_variety_extreme |
+----+---------------+-----------------------+
| 1 | 0 | 0 |
+----+---------------+-----------------------+
1 row in set (0.00 sec)
Then, with the trigger added to vitamin, inserted a couple of rows:
MariaDB [test]> insert into vitamin( vitamin_name, price ) values ('pilly 5', 7);
Query OK, 1 row affected (0.10 sec)
MariaDB [test]> insert into vitamin( vitamin_name, price ) values ('extreme pill 5', 3);
Query OK, 1 row affected (0.12 sec)
Show those inserts:
MariaDB [test]> select * from vitamin;
+----+----------------+-------+
| id | vitamin_name | price |
+----+----------------+-------+
| 8 | pilly 5 | 7 |
| 9 | extreme pill 5 | 3 |
+----+----------------+-------+
2 rows in set (0.00 sec)
Show the triggered price updates to the vitamin_variety table:
MariaDB [test]> select * from vitamin_variety;
+----+---------------+-----------------------+
| id | price_variety | price_variety_extreme |
+----+---------------+-----------------------+
| 1 | 7 | 3 |
+----+---------------+-----------------------+
1 row in set (0.00 sec)
=====
EDIT:
One possible way to achieve your goal, given this vitamin_variety table structure:
CREATE TABLE `vitamin_variety` (
`pill_name` varchar(25) NOT NULL,
`price_variety` int(11) NOT NULL DEFAULT '0',
`price_variety_extreme` int(11) NOT NULL DEFAULT '0',
UNIQUE KEY `pill_name` (`pill_name`)
);
Then changing the vitamin table trigger conditions to:
if new.vitamin_name like 'extreme%' then
insert into vitamin_variety (pill_name, price_variety_extreme)
values (replace(new.vitamin_name, 'extreme ', ''), new.price)
on duplicate key update price_variety_extreme = new.price;
else
insert into vitamin_variety (pill_name, price_variety)
values (new.vitamin_name, new.price)
on duplicate key update price_variety = new.price;
end if
Then running insert SQL based on your original vitamin table details:
MariaDB [test]> insert into vitamin (vitamin_name, price) values ('extreme pill 1', 10);
Query OK, 1 row affected (0.09 sec)
MariaDB [test]> insert into vitamin (vitamin_name, price) values ('pill 1', 5);
Query OK, 1 row affected (0.16 sec)
MariaDB [test]> insert into vitamin (vitamin_name, price) values ('extreme pill 2', 20);
Query OK, 1 row affected (0.10 sec)
MariaDB [test]> insert into vitamin (vitamin_name, price) values ('pill 2', 10);
Query OK, 1 row affected (0.10 sec)
Gives:
MariaDB [test]> select * from vitamin_variety;
+-----------+---------------+-----------------------+
| pill_name | price_variety | price_variety_extreme |
+-----------+---------------+-----------------------+
| pill 1 | 5 | 10 |
| pill 2 | 10 | 20 |
+-----------+---------------+-----------------------+
2 rows in set (0.00 sec)

Related

Enforce uniqueness within a date range or based on the value of another column

I have a table with a large amount of data; moving forward, I would like to enforce uniqueness for a given column in this table. However, the table contains a large amount of rows where that column is non-unique. I am not able to delete or alter these rows.
Is it possible to enforce uniqueness over a given date range, or since a specific date, or based on the value of another column (or something else like that) in MariaDB?
You can create a UNIQUE index on multiple columns, where one column is nullable. MariaDB will see each column with NULL values as a different value regarding the UNIQUE index, even if the other column values of the UNIQUE index are the same. Check the MariaDB documentation Getting Started with Indexes - Unique Index:
The fact that a UNIQUE constraint can be NULL is often overlooked. In SQL any NULL is never equal to anything, not even to another NULL. Consequently, a UNIQUE constraint will not prevent one from storing duplicate rows if they contain null values:
CREATE TABLE t1 (a INT NOT NULL, b INT, UNIQUE (a,b));
INSERT INTO t1 values (3,NULL), (3, NULL);
SELECT * FROM t1;
+---+------+
| a | b |
+---+------+
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | NULL |
| 3 | NULL |
+---+------+
You can create such a UNIQUE index on the date column you already have and a new column which indicates if the date value should be unique or not:
CREATE TABLE Foobar(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
createdAt DATE NOT NULL,
dateUniqueMarker BIT NULL DEFAULT 0,
UNIQUE KEY uq_createdAt(createdAt, dateUniqueMarker)
);
INSERT INTO Foobar(createdAt) VALUES ('2021-11-04'),('2021-11-05'),('2021-11-06');
SELECT * FROM Foobar;
+----+------------+------------------------------------+
| id | createdAt | dateUniqueMarker |
+----+------------+------------------------------------+
| 1 | 2021-11-04 | 0x00 |
| 2 | 2021-11-05 | 0x00 |
| 3 | 2021-11-06 | 0x00 |
+----+------------+------------------------------------+
INSERT INTO Foobar(createdAt) VALUES ('2021-11-05');
ERROR 1062 (23000): Duplicate entry '2021-11-05-\x00' for key 'Foobar.uq_createdAt'
UPDATE Foobar SET dateUniqueMarker = NULL WHERE createdAt = '2021-11-05';
INSERT INTO Foobar(createdAt, dateUniqueMarker) VALUES ('2021-11-05', NULL);
SELECT * FROM Foobar;
+----+------------+------------------------------------+
| id | createdAt | dateUniqueMarker |
+----+------------+------------------------------------+
| 1 | 2021-11-04 | 0x00 |
| 2 | 2021-11-05 | NULL |
| 5 | 2021-11-05 | NULL |
| 3 | 2021-11-06 | 0x00 |
+----+------------+------------------------------------+
Without any data example and scenario illustration, it's hard to know. If you can update your question with those information, please do.
"Is it possible to enforce uniqueness over a given date range, or since a specific date, or based on the value of another column (or something else like that) in MariaDB?"
If by "enforce" you mean to create a new column then populate it with unique identifier, then yes it is possible. If what you really mean is to generate a unique value based on other column, that's also possible. Question is, how unique do you want it to be?
Is it like this unique?
column1
column2
column3
unique_val
2021-02-02
ABC
DEF
1
2021-02-02
CBD
FEA
1
2021-02-03
BED
GER
2
2021-02-04
ART
TOY
3
2021-02-04
ZSE
KSL
3
Whereby if it's the same date (on column1), it should have the same unique value regardless of column2 & column3 data.
Or like this?
column1
column2
column3
unique_val
2021-02-02
ABC
DEF
1
2021-02-02
CBD
FEA
2
2021-02-03
BED
GER
3
2021-02-04
ART
TOY
4
2021-02-04
ZSE
KSL
5
Taking all (or certain) columns to consider the unique value.
Both of the scenario above can be achieved in query without the need to alter the table, adding and populate a new column but of course, the latter is also possible.

How to select the next 50 records from a specified row in an SQLite table

Consider that my SQLite table has the following schema,
|'''''''''''''''''''''''''''''''''''''
| unique_id(TXT) | object_data(BLOB) |
|'''''''''''''''''''''''''''''''''''''
| | |
| | |
| | |
''''''''''''''''''''''''''''''''''''''
Assume that the row_id property is enabled, and so my question is, for a given unique_id, is it possible to fetch the next 50 records from the table,
using a single SQL query? (Using the row_id property)
Try getting result through this method.
Select * from table_name [WHERE conditions] Limit 50 offset (Select row_id from table_name where unique_id = x);

How to create functional index on mariadb?

I'm trying to create functional index on mariadb 5.5 like below...
MariaDB [testdb]> create table foo(c1 datetime);
Query OK, 0 rows affected (0.43 sec)
MariaDB [testdb]> alter table foo add c2 varchar(10) AS (date_format(c1, '%Y-%m-%d'));
Query OK, 0 rows affected (0.22 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [testdb]> desc foo;
+-------+-------------+------+-----+---------+---------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+---------+
| c1 | datetime | YES | | NULL | |
| c2 | varchar(10) | YES | | NULL | VIRTUAL |
+-------+-------------+------+-----+---------+---------+
2 rows in set (0.03 sec)
MariaDB [testdb]> create index idx_foo on foo(c1, c2);
ERROR 1904 (HY000): Key/Index cannot be defined on a non-stored computed column
MariaDB [testdb]>
Is there any how to create compositional column based index with VIRUAL column?
Any advice would be appreciated.
Thanks in advance.
See documentation:
Generated (Virtual and Persistent/Stored) Columns
...
MariaDB until 10.2.2
In MariaDB 10.2.2 and before, the following statements apply to
indexes for generated columns:
Defining indexes on VIRTUAL generated columns is not supported.
...
...

What is the default server characterset in mariadb inside the Swisscom Cloud and how can it be changed?

This is a request for clarification concerning the Swisscom Cloud MariaDB Service. This is not about the generic MariaDB default charactersets.
I would like to know what the default character_set_server for the MariaDB Service on the Swisscom Cloud is defined as.
Assuming that it is actually latin1, I would like to know if this default can be changed (to utf-8 or more accurately utf8mb4 as it is for the debian mariadb package).
The main reason for my question is that I am having trouble creating backups that can easily be re-imported and I am getting widely different size output when extracting via mysqldump ... -r backup.sql compared to an export through Sequel Pro.
I don't use the tool Sequel Pro.
The legacy MariaDB/Galera cluster uses latin1 as default character set when you don't set it. This default setting is from upstream MariaDB developers. Most developers and DBAs don't like this decision.
Here is the CREATE TABLE syntax (see COLLATE and CHARACTER SET) :
CREATE TABLE tbl_name (column_list)
[[DEFAULT] CHARACTER SET charset_name]
[COLLATE collation_name]]
Server settings (this statement can every customer execute, no admin rights needed):
MariaDB [(none)]> show global variables like 'character_set%';
+--------------------------+-------------------------------------+
| Variable_name | Value |
+--------------------------+-------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mariadb-galera/charsets/ |
+--------------------------+-------------------------------------+
8 rows in set (0.00 sec)
If you still use legacy MariaDB, please hurry up and migrate your service instance. The legacy cluster will be in one or two days read-only.
We have a completely new MariaDB service in store for you. It comes
with many improvements (e.g. MariaDB version 10) and we recommend to
upgrade as soon as possible.
This step-by-step guide was created Aug 16, 2017.
The new cluster uses better default settings:
MariaDB [(none)]> show global variables like 'character_set%';
+--------------------------+------------------------------------------------------------------------------------------+
| Variable_name | Value |
+--------------------------+------------------------------------------------------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /var/vcap/data/packages/mariadb/95a1896c4bcdccb4e1abd81b7d00eb33aedb0da0/share/charsets/ |
+--------------------------+------------------------------------------------------------------------------------------+
8 rows in set (0.01 sec)
If you wish to change your character set and collation before importing the data into new cluster.
ALTER TABLE tbl_name
[[DEFAULT] CHARACTER SET charset_name]
[COLLATE collation_name]
We did this many times. Please keep in mind that you shouldn't do this with > 20000 records.
Please also have a look at our documentation for MariaDB
Please contact Swisscom Application Cloud support when you need to
issue long running DDL changes (for example ALTER TABLE with thousends
of records). Long running DDL causes an outage for all customers on
the cluster.
This is to demonstrate two different ALTERs; one does nothing useful; one does what you want:
-- Try the 'wrong' ALTER:
DROP TABLE IF EXISTS atc;
CREATE TABLE atc ( c VARCHAR(11)) CHARACTER SET latin1 ;
INSERT INTO atc (c) VALUES ('ÃÔäô');
SHOW CREATE TABLE atc\G
SELECT c, HEX(c) FROM atc; -- note the latin1 encoding
ALTER TABLE atc CHARACTER SET utf8;
SHOW CREATE TABLE atc\G -- the column stays latin1, overriding the table
SELECT c, HEX(c) FROM atc; -- still latin1 encoding
mysql>
mysql> -- Try the 'wrong' ALTER:
mysql>
mysql> DROP TABLE IF EXISTS atc;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE atc ( c VARCHAR(11)) CHARACTER SET latin1 ;
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO atc (c) VALUES ('ÃÔäô');
Query OK, 1 row affected (0.00 sec)
mysql> SHOW CREATE TABLE atc\G
*************************** 1. row ***************************
Table: atc
Create Table: CREATE TABLE `atc` (
`c` varchar(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> SELECT c, HEX(c) FROM atc; -- note the latin1 encoding
+----------+----------+
| c | HEX(c) |
+----------+----------+
| ÃÔäô | C3D4E4F4 |
+----------+----------+
1 row in set (0.00 sec)
mysql> ALTER TABLE atc CHARACTER SET utf8;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW CREATE TABLE atc\G -- the column stays latin1, overriding the table
*************************** 1. row ***************************
Table: atc
Create Table: CREATE TABLE `atc` (
`c` varchar(11) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SELECT c, HEX(c) FROM atc; -- still latin1 encoding
+----------+----------+
| c | HEX(c) |
+----------+----------+
| ÃÔäô | C3D4E4F4 |
+----------+----------+
1 row in set (0.00 sec)
-- Try the 'right' way:
DROP TABLE IF EXISTS atc;
CREATE TABLE atc ( c VARCHAR(11)) CHARACTER SET latin1 ;
INSERT INTO atc (c) VALUES ('ÃÔäô');
SHOW CREATE TABLE atc\G
SELECT c, HEX(c) FROM atc; -- note the latin1 encoding
ALTER TABLE atc CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE atc\G -- column and table are utf8
SELECT c, HEX(c) FROM atc; -- now utf8
mysql>
mysql> -- Try the 'right' way:
mysql>
mysql> DROP TABLE IF EXISTS atc;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE atc ( c VARCHAR(11)) CHARACTER SET latin1 ;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO atc (c) VALUES ('ÃÔäô');
Query OK, 1 row affected (0.00 sec)
mysql> SHOW CREATE TABLE atc\G
*************************** 1. row ***************************
Table: atc
Create Table: CREATE TABLE `atc` (
`c` varchar(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> SELECT c, HEX(c) FROM atc; -- note the latin1 encoding
+----------+----------+
| c | HEX(c) |
+----------+----------+
| ÃÔäô | C3D4E4F4 |
+----------+----------+
1 row in set (0.00 sec)
mysql> ALTER TABLE atc CONVERT TO CHARACTER SET utf8;
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SHOW CREATE TABLE atc\G -- column and table are utf8
*************************** 1. row ***************************
Table: atc
Create Table: CREATE TABLE `atc` (
`c` varchar(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SELECT c, HEX(c) FROM atc; -- now utf8
+----------+------------------+
| c | HEX(c) |
+----------+------------------+
| ÃÔäô | C383C394C3A4C3B4 |
+----------+------------------+
1 row in set (0.00 sec)
mysql>

MariaDB ALTER TABLE DROP COLUMN infinite

I use below command to drop a column activetime from my table. While this command never end. I waited for 5 mins while there is only 100 records in MY_TABLENAME
ALTER TABLE MY_TABLENAME DROP COLUMN activetime;
The column activetime is defined as below:
| activetime | bigint(20) | NO | | NULL | |

Resources