Too long alter/create table InnoDB - mariadb
I want to try InnoDB (change MyISAM engine). Insert/delete/update works fine (with transaction). Select looks good. Alter and create InnoDB tables is terrible.
Compare create/alter InnoDB and MyISAM tables:
MariaDB [temp_db]> CREATE TABLE `table_InnoDB` (
-> `id` int(10) unsigned NOT NULL DEFAULT 0,
-> `name` varchar(120) NOT NULL DEFAULT '',
-> `name_1` varchar(120) NOT NULL DEFAULT '',
-> `name_2` varchar(120) NOT NULL DEFAULT '',
-> `name_ms` varchar(250) NOT NULL DEFAULT '',
-> `name_ws` varchar(250) NOT NULL DEFAULT '',
-> `name_wa` varchar(250) NOT NULL DEFAULT '',
-> `name_t` varchar(250) NOT NULL DEFAULT '',
-> `name_o` varchar(250) NOT NULL DEFAULT '',
-> `street` varchar(250) NOT NULL DEFAULT '',
-> `street_t` varchar(250) NOT NULL DEFAULT '',
-> `lat` decimal(8,4) NOT NULL DEFAULT 0.0000,
-> `lng` decimal(8,4) NOT NULL DEFAULT 0.0000,
-> `latlng` varchar(15) NOT NULL DEFAULT '0',
-> `geohash` char(4) NOT NULL DEFAULT '',
-> `phone` varchar(50) NOT NULL DEFAULT '',
-> `website` varchar(100) NOT NULL DEFAULT '',
-> `facebook_id` varchar(32) NOT NULL DEFAULT '',
-> `city_id` int(10) unsigned NOT NULL DEFAULT 0,
-> `gd_city_id` int(10) unsigned NOT NULL DEFAULT 0
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (3.235 sec)
MariaDB [temp_db]> CREATE TABLE `table_MyISAM` (
-> `id` int(10) unsigned NOT NULL DEFAULT 0,
-> `name` varchar(120) NOT NULL DEFAULT '',
-> `name_1` varchar(120) NOT NULL DEFAULT '',
-> `name_2` varchar(120) NOT NULL DEFAULT '',
-> `name_ms` varchar(250) NOT NULL DEFAULT '',
-> `name_ws` varchar(250) NOT NULL DEFAULT '',
-> `name_wa` varchar(250) NOT NULL DEFAULT '',
-> `name_t` varchar(250) NOT NULL DEFAULT '',
-> `name_o` varchar(250) NOT NULL DEFAULT '',
-> `street` varchar(250) NOT NULL DEFAULT '',
-> `street_t` varchar(250) NOT NULL DEFAULT '',
-> `lat` decimal(8,4) NOT NULL DEFAULT 0.0000,
-> `lng` decimal(8,4) NOT NULL DEFAULT 0.0000,
-> `latlng` varchar(15) NOT NULL DEFAULT '0',
-> `geohash` char(4) NOT NULL DEFAULT '',
-> `phone` varchar(50) NOT NULL DEFAULT '',
-> `website` varchar(100) NOT NULL DEFAULT '',
-> `facebook_id` varchar(32) NOT NULL DEFAULT '',
-> `city_id` int(10) unsigned NOT NULL DEFAULT 0,
-> `gd_city_id` int(10) unsigned NOT NULL DEFAULT 0
-> ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.564 sec)
# alter empty tables
MariaDB [temp_db]> alter table `table_InnoDB`
-> add primary key (id),
-> add index (street(50), name(50)),
-> add index (street(50), city_id),
-> add index (street(50), gd_city_id),
-> add index (name(50), website),
-> add index (website, city_id),
-> add index (website, gd_city_id),
-> add index (phone, website),
-> add index (phone, name(50)),
-> add index (latlng, name(50)),
-> add index (city_id, name(50)),
-> add index (gd_city_id, name(50)),
-> add index (name_t(50), street(50)),
-> add index (street_t(50), name_t(50)),
-> add index (name_t(50), website),
-> add index (name_t(50), phone);
Query OK, 0 rows affected (11.812 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> alter table `table_MyISAM`
-> add primary key (id),
-> add index (street(50), name(50)),
-> add index (street(50), city_id),
-> add index (street(50), gd_city_id),
-> add index (name(50), website),
-> add index (website, city_id),
-> add index (website, gd_city_id),
-> add index (phone, website),
-> add index (phone, name(50)),
-> add index (latlng, name(50)),
-> add index (city_id, name(50)),
-> add index (gd_city_id, name(50)),
-> add index (name_t(50), street(50)),
-> add index (street_t(50), name_t(50)),
-> add index (name_t(50), website),
-> add index (name_t(50), phone);
Query OK, 0 rows affected (0.681 sec)
Records: 0 Duplicates: 0 Warnings: 0
# still empty tables
MariaDB [temp_db]> ALTER TABLE `table_InnoDB`
-> DROP PRIMARY KEY,
-> DROP INDEX `name_t_3`,
-> DROP INDEX `name_t_2`,
-> DROP INDEX `street_t`,
-> DROP INDEX `name_t`,
-> DROP INDEX `gd_city_id`,
-> DROP INDEX `city_id`,
-> DROP INDEX `latlng`,
-> DROP INDEX `phone_2`,
-> DROP INDEX `phone`,
-> DROP INDEX `website_2`,
-> DROP INDEX `website`,
-> DROP INDEX `name`,
-> DROP INDEX `street_3`,
-> DROP INDEX `street_2`,
-> DROP INDEX `street`;
Query OK, 0 rows affected (6.149 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> ALTER TABLE `table_MyISAM`
-> DROP PRIMARY KEY,
-> DROP INDEX `name_t_3`,
-> DROP INDEX `name_t_2`,
-> DROP INDEX `street_t`,
-> DROP INDEX `name_t`,
-> DROP INDEX `gd_city_id`,
-> DROP INDEX `city_id`,
-> DROP INDEX `latlng`,
-> DROP INDEX `phone_2`,
-> DROP INDEX `phone`,
-> DROP INDEX `website_2`,
-> DROP INDEX `website`,
-> DROP INDEX `name`,
-> DROP INDEX `street_3`,
-> DROP INDEX `street_2`,
-> DROP INDEX `street`;
Query OK, 0 rows affected (0.730 sec)
Records: 0 Duplicates: 0 Warnings: 0
# insert data
MariaDB [temp_db]> INSERT table_InnoDB (`id`, `name`, `name_1`, `name_2`, `name_ms`, `name_ws`, `name_wa`, `name_t`, `name_o`, `street`, `street_t`, `lat`, `lng`, `latlng`, `geohash`, `phone`, `website`, `facebook_id`, `city_id`, `gd_city_id`) SELECT `id`, `name`, `name_1`, `name_2`, `name_ms`, `name_ws`, `name_wa`, `name_t`, `name_o`, `street`, `street_t`, `lat`, `lng`, `latlng`, `geohash`, `phone`, `website`, `facebook_id`, `city_id`, `gd_city_id` FROM test_data;
Query OK, 127451 rows affected (53.041 sec)
Records: 127451 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> INSERT table_MyISAM (`id`, `name`, `name_1`, `name_2`, `name_ms`, `name_ws`, `name_wa`, `name_t`, `name_o`, `street`, `street_t`, `lat`, `lng`, `latlng`, `geohash`, `phone`, `website`, `facebook_id`, `city_id`, `gd_city_id`) SELECT `id`, `name`, `name_1`, `name_2`, `name_ms`, `name_ws`, `name_wa`, `name_t`, `name_o`, `street`, `street_t`, `lat`, `lng`, `latlng`, `geohash`, `phone`, `website`, `facebook_id`, `city_id`, `gd_city_id` FROM test_data;
Query OK, 127451 rows affected (1.125 sec)
Records: 127451 Duplicates: 0 Warnings: 0
# alter tables with 127451 rows
MariaDB [temp_db]> alter table `table_InnoDB`
-> add primary key (id),
-> add index (street(50), name(50)),
-> add index (street(50), city_id),
-> add index (street(50), gd_city_id),
-> add index (name(50), website),
-> add index (website, city_id),
-> add index (website, gd_city_id),
-> add index (phone, website),
-> add index (phone, name(50)),
-> add index (latlng, name(50)),
-> add index (city_id, name(50)),
-> add index (gd_city_id, name(50)),
-> add index (name_t(50), street(50)),
-> add index (street_t(50), name_t(50)),
-> add index (name_t(50), website),
-> add index (name_t(50), phone);
Query OK, 0 rows affected (32 min 33.282 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> alter table `table_MyISAM`
-> add primary key (id),
-> add index (street(50), name(50)),
-> add index (street(50), city_id),
-> add index (street(50), gd_city_id),
-> add index (name(50), website),
-> add index (website, city_id),
-> add index (website, gd_city_id),
-> add index (phone, website),
-> add index (phone, name(50)),
-> add index (latlng, name(50)),
-> add index (city_id, name(50)),
-> add index (gd_city_id, name(50)),
-> add index (name_t(50), street(50)),
-> add index (street_t(50), name_t(50)),
-> add index (name_t(50), website),
-> add index (name_t(50), phone);
Query OK, 127451 rows affected (5.976 sec)
Records: 127451 Duplicates: 0 Warnings: 0
10.3.13-MariaDB config:
datadir=/var/lib/mysql
tmpdir = /mnt/ssd/tmp/
socket=/var/lib/mysql/mysql.sock
symbolic-links=1
key_buffer_size = 1G
max_connections = 300
max_user_connections = 280
table_open_cache = 42192
open_files_limit = 165832
max_allowed_packet = 16M
log_warnings = 0
extra_port = 3307
extra_max_connections = 4
sql_mode = NO_ENGINE_SUBSTITUTION
performance_schema = ON
###############innodb###############
innodb_file_per_table = ON
innodb_sort_buffer_size = 8M
innodb_buffer_pool_size = 15G
innodb_buffer_pool_instances = 15
innodb_write_io_threads = 8
innodb_read_io_threads = 8
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2
####################################
sort_buffer_size = 12M
read_buffer_size = 2M
join_buffer_size = 4M
thread_cache_size = 256
thread_stack=512K
thread_handling = one-thread-per-connection
thread_pool_max_threads = 500
read_rnd_buffer_size = 16M
net_buffer_length = 1048576
net_read_timeout = 600
net_write_timeout = 600
myisam_sort_buffer_size = 128M
aria_sort_buffer_size = 2G
aria_pagecache_buffer_size = 2G
query_cache_type = OFF
max_heap_table_size = 512M
tmp_table_size = 512M
character-set-server=utf8
collation-server=utf8_general_ci
init-connect="SET NAMES utf8"
default_storage_engine="MyISAM"
slow_query_log_file = /var/log/mariadb/mariadb-slow.log
long-query-time = 5
slow_query_log = 0
skip-name-resolve
low_priority_updates = 1
During alter table SSD busy 100%, but have only several hundred iops and several MB/s read/write.
Other test: Server vs myworkstation
Server (SSD busy 100% after alter tables engine=InnoDB: several light cron scripts + replication):
MariaDB [temp_db]> ALTER TABLE `temp_db`.`table_MyISAM` ADD COLUMN `tmp` VARCHAR(45) NOT NULL DEFAULT '' AFTER `gd_city_id`;
Query OK, 127451 rows affected (6.149 sec)
Records: 127451 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> ALTER TABLE `temp_db`.`table_InnoDB` ADD COLUMN `tmp` VARCHAR(45) NOT NULL DEFAULT '' AFTER `gd_city_id`;
Query OK, 0 rows affected (11.830 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> ALTER TABLE `table_MyISAM` DROP COLUMN `tmp`;
Query OK, 127451 rows affected (5.182 sec)
Records: 127451 Duplicates: 0 Warnings: 0
MariaDB [temp_db]> ALTER TABLE `table_InnoDB` DROP COLUMN `tmp`;
Query OK, 0 rows affected (18 min 36.757 sec)
Records: 0 Duplicates: 0 Warnings: 0
my PC:
MariaDB [test]> ALTER TABLE `table_MyISAM` ADD COLUMN `tmp` VARCHAR(45) NOT NULL DEFAULT '' AFTER `gd_city_id`;
Query OK, 127451 rows affected (2.897 sec)
Records: 127451 Duplicates: 0 Warnings: 0
MariaDB [test]> ALTER TABLE `table_InnoDB` ADD COLUMN `tmp` VARCHAR(45) NOT NULL DEFAULT '' AFTER `gd_city_id`;
Query OK, 0 rows affected (0.009 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [test]> ALTER TABLE `table_MyISAM` DROP COLUMN `tmp`;
Query OK, 127451 rows affected (2.822 sec)
Records: 127451 Duplicates: 0 Warnings: 0
MariaDB [test]> ALTER TABLE `table_InnoDB` DROP COLUMN `tmp`;
Query OK, 0 rows affected (2.879 sec)
Records: 0 Duplicates: 0 Warnings: 0
Server: 49GB RAM, 32 CPU.
Related
Constraints about
What constraints are copied with table when we create table by using create table as select statement..?
I don't know about MySQL, but - as of Oracle - only the NOT NULL constraint. Even if there was a column designed as a primary key (which - implicitly - means that it can't be NULL), newly created table won't have that constraint. For example: SQL> create table test_1 2 (id number primary key, 3 name varchar2(20) not null); Table created. SQL> select constraint_name, constraint_Type from user_constraints where table_name = 'TEST_1'; CONSTRAINT_NAME C -------------------- - SYS_C009194 C --> "C"heck (NOT NULL) constraint SYS_C009195 P --> "P"rimary key constraint SQL> create table test_2 as select * from test_1; Table created. SQL> select constraint_name, constraint_Type from user_constraints where table_name = 'TEST_2'; CONSTRAINT_NAME C -------------------- - SYS_C009196 C --> that's the "C"heck - NOT NULL constraint SQL> desc test_2 Name Null? Type ----------------------------------------- -------- ---------------------------- ID NUMBER NAME NOT NULL VARCHAR2(20) SQL>
MySQL would only preserve NOT NULL as constarint CREATE TABLE tab1(id int AUTO_INCREMENT PRIMARY KEY) create table tab2 (id int primary key, col1 varchar(20) not null, col2 int UNIQUE, col3 int, FOREIGN KEY (col3) REFERENCES tab1(id)) CREATE TABLE tab3 AS SELECT * FROM tab2 Records: 0 Duplicates: 0 Warnings: 0 SHOW CREATE TABLE tab3 Table Create Table tab3 CREATE TABLE `tab3` ( `id` int NOT NULL, `col1` varchar(20) NOT NULL, `col2` int DEFAULT NULL, `col3` int DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci fiddle
MARIADB sequences - incrementing by 2
I have the following MARIADB code. It's supposed to demonstrate: Constructing tables using sequences for incrementing the ID. Using a temporary table+join to INSERT data into a table, while incrementing the ID. Procedure: Sequence S1 and table T1 are created. T1_ID is incremented with S1 Sequence S2 and table T2 are created. T2_ID is incremented with S2 Table T1 is filled with data. All is fine. Temporary table TEMP_T2 is created and filled with data. No ID in this table. Column T1_NAME is a cross reference to SHORT_NAME in table T1. The T1_ID is introduced into table TEMP_T2 with a join. The result of this SELECT is inserted into T2. Here, the sequence S2 should auto-increment T2_ID. For some reason, at the end, T2 looks like this: T2_ID|T1_ID|NAME| -----+-----+----+ 2| 1|y | 4| 2|x | 6| 2|z | Why was T2_ID double-incremented? Thanks! USE DB1; SET FOREIGN_KEY_CHECKS = 0; DROP SEQUENCE IF EXISTS `S2`; DROP SEQUENCE IF EXISTS `S1`; DROP TABLE IF EXISTS `T2`; DROP TABLE IF EXISTS `T1`; -- Create sequence S1 and able T1 CREATE SEQUENCE `S1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; SELECT SETVAL(`S1`, 1, 0); CREATE TABLE `T1` ( `T1_ID` tinyint(4) NOT NULL DEFAULT nextval(`S1`), `SHORT_NAME` varchar(10) NOT NULL, PRIMARY KEY (`T1_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; -- Create sequence T2 and table T2 CREATE SEQUENCE `S2` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; SELECT SETVAL(`S2`, 1, 0); CREATE TABLE `T2` ( `T2_ID` int(11) NOT NULL DEFAULT nextval(`S2`), `T1_ID` int(11) DEFAULT NULL, `NAME` varchar(100) DEFAULT NULL COLLATE 'utf8mb3_bin', PRIMARY KEY (`T2_ID`), UNIQUE KEY `T2_NAME_UN` (`NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; -- Load data into T1 DELETE FROM T1; INSERT INTO T1(SHORT_NAME) VALUES ('a'), ('b'), ('c'); SELECT * FROM T1; -- Create temporary file for joining with T1 DROP TABLE IF EXISTS `TEMP_T2`; CREATE TEMPORARY TABLE `TEMP_T2` ( `T1_NAME` varchar(10) DEFAULT NULL, `NAME` varchar(100) DEFAULT NULL, UNIQUE KEY `T2_NAME_UN` (`NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; DELETE FROM TEMP_T2 ; -- Insert data into the temporary table INSERT INTO TEMP_T2(T1_NAME,NAME) VALUES ('b','x'), ('a','y'), ('b','z'); SELECT * FROM TEMP_T2; # Do a join with TEMP_T2 x T1 and insert into T2 INSERT INTO T2(T1_ID,NAME) SELECT t1.T1_ID , t2.NAME FROM TEMP_T2 AS t2 INNER JOIN T1 AS t1 ON t2.T1_NAME =t1.SHORT_NAME ; SELECT * FROM T2;
Thanks for the responses. I'm using SEQUENCE rather than AUTO_INCREMENT because I was told that it is the more modern way. It also enables retrieving the last ID of any specific table. It's strange that this should be a bug. It seems like really basic functionality. But so it is...
I've found this as a reported existing bug MDEV-29540 in INSERT ... SELECT as it pertains to sequences in default values of columns. Because this bug is reported and fix, this problem is/will not occur in the 10.3.37, 10.4.27, 10.5.18, 10.6.11, 10.7.7, 10.8.6, 10.9.4, 10.10.2, 10.11.1 and later versions.
MariaDB limit value of column
I want to limit the value of the column limited_column, where 0 >= limited_column <= 100 SQL side, on MariaDB I've tried creating a trigger on INSERT ad UPDATE as such: DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `username` varchar(25) NOT NULL, `user_id` int(100) NOT NULL, `limited_column` bigint(20) unsigned NOT NULL DEFAULT '0', [...] PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; DELIMITER $$ CREATE TRIGGER `limited_column_check_on_insert_trigger` BEFORE INSERT ON `users` FOR EACH ROW BEGIN DECLARE dummy,baddataflag INT; SET baddataflag = 0; IF NEW.limited_column > 100 THEN SET baddataflag = 1; END IF; IF NEW.limited_column < 0 THEN SET baddataflag = 1; END IF; IF baddataflag = 1 THEN SELECT CONCAT('Cannot INSERT new value because limited_column is > 100, value was ',NEW.limited_column) INTO dummy FROM information_schema.tables; END IF; END; $$ CREATE TRIGGER `limited_column_check_on_update_trigger` BEFORE UPDATE ON `users` FOR EACH ROW BEGIN DECLARE dummy,baddataflag INT; SET baddataflag = 0; IF NEW.limited_column > 100 THEN SET baddataflag = 1; END IF; IF NEW.limited_column < 0 THEN SET baddataflag = 1; END IF; IF baddataflag = 1 THEN SELECT CONCAT('Cannot UPDATE new value because limited_column is > 100, value was ',NEW.limited_column) INTO dummy FROM information_schema.tables; END IF; END; $$ DELIMITER ; This is what I get if I try inserting a new user when limited_column > 100 (limited_column > 100 works): MariaDB [NameOfADatabase]> INSERT INTO users (username,user_id,limited_column,[...]) VALUES ('testestes',1,1000,[...]); ERROR 1172 (42000): Result consisted of more than one row MariaDB [NameOfADatabase]> INSERT INTO users (username,user_id,limited_column,[...]) VALUES ('testestes',2,100,[...]); Query OK, 1 row affected (0.02 sec) Any ideas on what I can do to make this more graceful? This is running on 10.1.38-MariaDB-0ubuntu0.18.04.2 Ubuntu 18.04
Upgrading to 10.3.15 was the best solution for this, as I can use the CHECK option. Thanks to #RickJames for the info about the update. Here's the Schema I'm using that works: DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `username` varchar(25) NOT NULL, `user_id` int(100) NOT NULL, `limited_column` bigint(20) unsigned NOT NULL DEFAULT '0', [...] PRIMARY KEY (`user_id`), CHECK (limited_column<=100) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; Here's the output I get: MariaDB [NameOfADatabase]> INSERT INTO users (username,user_id,limited_column,[...]) VALUES ('test1',1,100,[...]); Query OK, 1 row affected (0.016 sec) MariaDB [NameOfADatabase]> INSERT INTO users (username,user_id,limited_column,[...]) VALUES ('test2',2,101,[...]); ERROR 4025 (23000): CONSTRAINT `CONSTRAINT_1` failed for `NameOfADatabase`.`users`
Mariadb check constraint with subquerie on current table
Is it possible to do check constraint with subquery on maria db table like this: CREATE TABLE `tbl` ( `id` int NOT NULL, `start` datetime NOT NULL, `end` datetime NOT NULL, CONSTRAINT C1 CHECK (id not in (select id from tbl as tt where tt.start between start and end or tt.end between start and end)), CONSTRAINT C2 CHECK (end>start) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; I got error: ERROR 1146 (42S02): Table 'test.tbl' doesn't exist
You're trying to access an object that doesn't exist (Table 'tbl'), you are trying to create it: MariaDB [_]> DROP TABLE IF EXISTS `tbl`; Query OK, 0 rows affected (0.01 sec) MariaDB [_]> CREATE TABLE IF NOT EXISTS `tbl` ( -> `id` INT NOT NULL, -> `start` DATETIME NOT NULL, -> `end` DATETIME NOT NULL, -> CONSTRAINT `C1` CHECK (`id` NOT IN -> (SELECT `id` -> FROM `tbl` AS `tt` -> WHERE `tt`.`start` BETWEEN `start` AND `end` OR -> `tt`.`end` BETWEEN `start` AND `end`) -> ), -> CONSTRAINT `C2` CHECK (`end` > `start`) -> ); ERROR 1146 (42S02): Table '_.tbl' doesn't exist In case of access to an object that does exist: MariaDB [_]> DROP TABLE IF EXISTS `tbl_TEMP`, `tbl`; Query OK, 0 rows affected, 2 warnings (0.00 sec) MariaDB [_]> CREATE TABLE IF NOT EXISTS `tbl_TEMP` ( -> `id` INT NOT NULL, -> `start` DATETIME NOT NULL, -> `end` DATETIME NOT NULL -> ); Query OK, 0 rows affected (0.00 sec) MariaDB [_]> CREATE TABLE IF NOT EXISTS `tbl` ( -> `id` INT NOT NULL, -> `start` DATETIME NOT NULL, -> `end` DATETIME NOT NULL, -> CONSTRAINT `C1` CHECK ( -> `id` NOT IN (SELECT `id` -> FROM `tbl_TEMP` AS `tt` -> WHERE `tt`.`start` BETWEEN `start` AND `end` OR -> `tt`.`end` BETWEEN `start` AND `end`) -> ), -> CONSTRAINT `C2` CHECK (`end` > `start`) -> ); ERROR 1901 (HY000): Function or expression 'select ...' cannot be used in the CHECK clause of `C1` An option that may be useful: MariaDB [_]> DROP TABLE IF EXISTS `tbl`; Query OK, 0 rows affected, 1 warning (0.00 sec) MariaDB [_]> CREATE TABLE IF NOT EXISTS `tbl` ( -> `id` INT NOT NULL, -> `start` DATETIME NOT NULL, -> `end` DATETIME NOT NULL, -> CONSTRAINT `C2` CHECK (`end` > `start`) -> ); Query OK, 0 rows affected (0.00 sec) MariaDB [_]> DELIMITER // MariaDB [_]> CREATE TRIGGER `trg_bi_idduplicate` BEFORE INSERT ON `tbl` -> FOR EACH ROW -> BEGIN -> IF EXISTS (SELECT NULL -> FROM `tbl` -> WHERE `id` = NEW.`id`) THEN -> SIGNAL SQLSTATE '45000' SET -> MYSQL_ERRNO = 31001, -> MESSAGE_TEXT = '`id` DUPLICATE'; -> END IF; -> END// Query OK, 0 rows affected (0.00 sec) MariaDB [_]> DELIMITER ; MariaDB [_]> INSERT INTO `tbl` -> SELECT 1, '2000-01-01 00:00:01', '2000-01-01 00:00:01'; ERROR 4025 (23000): CONSTRAINT `C2` failed for `_`.`tbl` MariaDB [_]> INSERT INTO `tbl` -> SELECT 1, '2000-01-01 00:00:01', '2000-01-01 00:00:02'; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 MariaDB [_]> SELECT -> `id`, -> `start`, -> `end` -> FROM -> `tbl`; +----+---------------------+---------------------+ | id | start | end | +----+---------------------+---------------------+ | 1 | 2000-01-01 00:00:01 | 2000-01-01 00:00:02 | +----+---------------------+---------------------+ 1 row in set (0.00 sec) MariaDB [_]> INSERT INTO `tbl` -> SELECT 1, '2000-01-01 00:00:01', '2000-01-01 00:00:02'; ERROR 31001 (45000): `id` DUPLICATE MariaDB [_]> SELECT -> `id`, -> `start`, -> `end` -> FROM -> `tbl`; +----+---------------------+---------------------+ | id | start | end | +----+---------------------+---------------------+ | 1 | 2000-01-01 00:00:01 | 2000-01-01 00:00:02 | +----+---------------------+---------------------+ 1 row in set (0.00 sec)
Creating stored procedure giving error
I have created a stored procedure create or replace PROCEDURE "USP_USER_ADD" ( USERNAME IN VARCHAR2 , P_PASSWORD IN VARCHAR2 , SALT IN BLOB , EMAIL IN VARCHAR2 , FIRST_NAME IN VARCHAR2 , LAST_NAME IN VARCHAR2 , ip_address IN VARCHAR2 , EMAIL_VERIFIED IN NUMBER , ACTIVE IN NUMBER , CREATEDBY IN VARCHAR2 , CREATED IN DATE , MODIFIED IN DATE , MODIFIEDBY IN VARCHAR2 , USER_GROUP_ID IN NUMBER , LAST_PASSWORD_CHANGE_DATE IN DATE , P_failed_login_attempts IN NUMBER ) AS BEGIN declare user_id_tmp number(20); INSERT INTO users( "username" , "password" , "salt" , "email" , "first_name" , "last_name" , "email_verified" , "active" , "ip_address" , "created" , "createdby" , "modified" , "modifiedby" , "user_group_id" , "last_password_change_date" , "FAILED_LOGIN_ATTEMPTS" ) VALUES ( username , p_password , salt , email , first_name , last_name , email_verified , active , ip_address , created , createdby , modified , modifiedby , user_group_id , last_password_change_date , p_failed_login_attempts ); SELECT MAX(id) INTO user_id_tmp FROM users ; INSERT INTO user_passwords ( "user_id" , "password" , "created" ) VALUES ( user_id_tmp, p_password, created ); END USP_USER_ADD; It's giving me two errors 1: Error(26,5): PLS-00103: Encountered the symbol "INSERT" when expecting one of the following: begin function package pragma procedure subtype type use form current cursor The symbol "begin" was substituted for "INSERT" to continue. 2: Error(78,19): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe These are my tables -------------------------------------------------------- -- DDL for Table USER_PASSWORDS -------------------------------------------------------- CREATE TABLE "NEWS1.0"."USER_PASSWORDS" ( "ID" NUMBER(11,0), "USER_ID" NUMBER(11,0), "PASSWORD" VARCHAR2(255 BYTE), "SALT" VARCHAR2(255 BYTE), "IP" VARCHAR2(15 BYTE), "CREATEDBY" VARCHAR2(255 BYTE), "CREATED" DATE, "MODIFIED" DATE, "MODIFIEDBY" VARCHAR2(255 BYTE) ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ; -------------------------------------------------------- -- DDL for Index USERS_PK -------------------------------------------------------- CREATE UNIQUE INDEX "NEWS1.0"."USERS_PK" ON "NEWS1.0"."USER_PASSWORDS" ("ID") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ; -------------------------------------------------------- -- Constraints for Table USER_PASSWORDS -------------------------------------------------------- ALTER TABLE "NEWS1.0"."USER_PASSWORDS" MODIFY ("ID" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USER_PASSWORDS" MODIFY ("USER_ID" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USER_PASSWORDS" MODIFY ("PASSWORD" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USER_PASSWORDS" ADD CONSTRAINT "USERS_PK" PRIMARY KEY ("ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE; -------------------------------------------------------- -- DDL for Trigger BI_USER_PASSWORDS_ID -------------------------------------------------------- CREATE OR REPLACE TRIGGER "NEWS1.0"."BI_USER_PASSWORDS_ID" before insert on "USER_PASSWORDS" for each row begin if inserting then if :NEW."ID" is null then select USER_PASSWORDS_SEQ.nextval into :NEW."ID" from dual; end if; end if; end; / ALTER TRIGGER "NEWS1.0"."BI_USER_PASSWORDS_ID" ENABLE; -------------------------------------------------------- -- DDL for Table USERS -------------------------------------------------------- CREATE TABLE "NEWS1.0"."USERS" ( "ID" NUMBER(*,0), "USERNAME" VARCHAR2(100 BYTE), "PASSWORD" VARCHAR2(255 BYTE), "SALT" BLOB, "EMAIL" VARCHAR2(100 BYTE), "FIRST_NAME" VARCHAR2(100 BYTE), "LAST_NAME" VARCHAR2(100 BYTE), "EMAIL_VERIFIED" NUMBER(*,0) DEFAULT 1, "ACTIVE" NUMBER(*,0) DEFAULT 1, "IP_ADDRESS" VARCHAR2(50 BYTE), "USER_GROUP_ID" NUMBER(*,0), "LAST_PASSWORD_CHANGE_DATE" DATE, "FAILED_LOGIN_ATTEMPTS" NUMBER(*,0), "CREATED" DATE, "CREATEDBY" VARCHAR2(255 BYTE), "MODIFIED" DATE, "MODIFIEDBY" VARCHAR2(255 BYTE) ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" LOB ("SALT") STORE AS ( TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10 NOCACHE LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)) ; -------------------------------------------------------- -- DDL for Index USERS_UK2 -------------------------------------------------------- CREATE UNIQUE INDEX "NEWS1.0"."USERS_UK2" ON "NEWS1.0"."USERS" ("EMAIL") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ; -------------------------------------------------------- -- DDL for Index USERS_UK1 -------------------------------------------------------- CREATE UNIQUE INDEX "NEWS1.0"."USERS_UK1" ON "NEWS1.0"."USERS" ("USERNAME") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ; -------------------------------------------------------- -- Constraints for Table USERS -------------------------------------------------------- ALTER TABLE "NEWS1.0"."USERS" MODIFY ("ID" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USERS" MODIFY ("USERNAME" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USERS" MODIFY ("PASSWORD" NOT NULL ENABLE); ALTER TABLE "NEWS1.0"."USERS" ADD CONSTRAINT "USERS_UK1" UNIQUE ("USERNAME") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE; ALTER TABLE "NEWS1.0"."USERS" ADD CONSTRAINT "USERS_UK2" UNIQUE ("EMAIL") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE;
The problem is in this section of code: P_failed_login_attempts IN NUMBER ) AS BEGIN declare user_id_tmp number(20); INSERT INTO users( "username" , -- rest omitted Remove the declare and move the declaration of user_id between the AS and the BEGIN: P_failed_login_attempts IN NUMBER ) AS user_id_tmp number(20); BEGIN INSERT INTO users( "username" , -- rest omitted In Oracle PL/SQL, a block has the form DECLARE -- some variable declarations BEGIN -- some code EXCEPTION -- some exception-handling END; The variable declarations and exception-handling sections are optional. If there are no variable declarations, you can remove the keyword DECLARE (it's not an error if you leave it there). However, if the block has no exception handling, the EXCEPTION keyword must be removed. When declaring a procedure or function, the CREATE OR REPLACE PROCEDURE ... AS part takes the place of a DECLARE. The -- some code section of a PL/SQL block can contain further blocks inside it. In fact, this is what the PL/SQL compiler thought you wanted when it saw your declare keyword. It thought you were doing something like the following: CREATE OR REPLACE PROCEDURE USP_USER_ADD ( -- parameters omitted ) AS BEGIN DECLARE -- some variable declarations BEGIN -- some code END; END USP_USER_ADD; However, you had an INSERT after the declare. The compiler wasn't expecting that, and that's why you got an error. You also got an error about end-of-file, and that was because the PL/SQL compiler was expecting two ENDs but got to the end of your stored procedure before it found the second one.
I think that you should remove DECLARE. Oracle 11g Create Procedure Documentation
Previous answers have cleared up the compile errors, so I won't address those. But you have a potential bug in place; the id inserted into "user_password" table may not be the same as in "user" table In a multi-user environment it is possible another user could insert and commit into after you insert into set but before you do the select max. That would hopefully raise dup-val-on-index, but would be extremely difficult to find. You can remove this possibility, and have slightly less/cleaner(?) code by getting the id assigned by a trigger?) by using the return option on the insert itself: insert into user ( ... ) values (...) returning id into user_id_tmp ; and delete the select max(id) ... statement.