MariaDB, How to copy existing records using insert? - sql

I have a lot of existing records which I want to copy using an INSERT, for example if I have a query:
SELECT * FROM `threats` WHERE biDataset=9;
The common key is biDataset, the primary key in this table is biPK which is auto incremented on each insert. Here is the table structure:
CREATE TABLE `threats` (
`biPK` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
`biDataset` BIGINT(20) UNSIGNED NOT NULL COMMENT 'ID of dataset',
`jsonParams` LONGTEXT NOT NULL COMMENT 'JSON object containing all parameters' COLLATE 'utf8mb4_bin',
`txtTrainee` MEDIUMTEXT NULL DEFAULT NULL COMMENT 'Trainee host name (NULL if not applicable)' COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`biPK`) USING BTREE,
UNIQUE INDEX `dataset and json` (`biDataset`, `jsonParams`) USING HASH,
INDEX `datasetIdx` (`biDataset`) USING BTREE,
INDEX `jsonIdx` (`jsonParams`(768)) USING BTREE
)
COMMENT='Table of datasets'
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=174;
What I want to do is copy all the records that exist where biDataset is 9, creating new records, I need to be able to specify the new biDataset too, 15 to use for all copies instead of 9.
I've tried:
INSERT INTO `threats` (biDataset, txtTrainee, jsonParams)
SELECT 15, NULL, jsonParams FROM `threats` WHERE biDataset=9;
This results in:
SQL Error (1364): Field 'DB_ROW_HASH_1' doesn't have a default value

The solution was to modify the table structure to:
CREATE TABLE `threats` (
`biPK` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
`biDataset` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'ID of dataset',
`jsonParams` LONGTEXT NULL DEFAULT NULL COMMENT 'JSON object containing all parameters' COLLATE 'utf8mb4_bin',
`txtTrainee` MEDIUMTEXT NULL DEFAULT NULL COMMENT 'Trainee host name (NULL if not applicable)' COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`biPK`) USING BTREE,
UNIQUE INDEX `dataset and json` (`biDataset`, `jsonParams`) USING HASH,
INDEX `datasetIdx` (`biDataset`) USING BTREE,
INDEX `jsonIdx` (`jsonParams`(768)) USING BTREE
)
COMMENT='Table of datasets'
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=174
;

This is bug of mariadb, and it is still unresolved...
Checkout: https://jira.mariadb.org/browse/MDEV-22756

Related

RegEx - How to select all text in between backes (multiline)

Basically, what i want to do is to parse a *.sql file and select all CREATE TABLE Statements. Example below:
-- ----------------------------
-- Table structure for aes_interval
-- ----------------------------
DROP TABLE IF EXISTS `aes_interval`;
CREATE TABLE `aes_interval` (
`processcode` bigint(20) NOT NULL,
`overstaying` int(11) NOT NULL,
`floating` int(11) NOT NULL,
PRIMARY KEY (`processcode`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci;
by running a RegEx that would select all in between (...) i will be able to get an output/substringed text like below:
CREATE TABLE `aes_interval` (
`processcode` bigint(20) NOT NULL,
`overstaying` int(11) NOT NULL,
`floating` int(11) NOT NULL,
PRIMARY KEY (`processcode`) USING BTREE
)
i've tried CREATE TABLE\w+\((.|\n)*?\) but it only returns the output below:
CREATE TABLE `aes_interval` (
`processcode` bigint(20)
hopefully, i can pick up the proper regex here.
Assuming the CREATE TABLE statements are terminated by semicolon, and therefore that semicolon does not appear until the end of each statement, then the following regex should work:
(CREATE TABLE.*?;)
There is a caveat that the above would need to run in a tool/language with dot configured to match newline. And also multiline match mode would need to be enabled.
Demo
Edit:
I suspect that lazy dot is not working on Sublime Text. If so, then you can try the following pattern:
(CREATE TABLE[^;]*)
You can try this (CREATE TABLE.*?((\(.*?\)).*?)+\)) in https://regex101.com/

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server

I was trying to run following Query on my sql server :
CREATE TABLE `e_store`.`products`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(250) NOT NULL ,
`brand_id` INT UNSIGNED NOT NULL ,
`category_id` INT UNSIGNED NOT NULL ,
`attributes` JSON NOT NULL ,
PRIMARY KEY(`id`) ,
INDEX `CATEGORY_ID`(`category_id` ASC) ,
INDEX `BRAND_ID`(`brand_id` ASC) ,
CONSTRAINT `brand_id` FOREIGN KEY(`brand_id`) REFERENCES `e_store`.`brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE ,
CONSTRAINT `category_id` FOREIGN KEY(`category_id`) REFERENCES `e_store`.`categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE
);
I have already brands and categories tables on my e_store database.
But I got the following Error :
#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 'JSON NOT NULL ,
PRIMARY KEY(`id`) ,
INDEX `CATEGORY_ID`('category_id' ' at line 6
For those who are facing this issue similar to me:
MariaDB does not natively implement the JSON data type but it uses it as an alias for LONGTEXT for compatibility reasons. According to the documentation (https://mariadb.com/kb/en/library/json-data-type/):
JSON is an alias for LONGTEXT introduced for compatibility reasons with MySQL's JSON data type. MariaDB implements this as a LONGTEXT rather, as the JSON data type contradicts the SQL standard, and MariaDB's benchmarks indicate that performance is at least equivalent.
In order to ensure that a a valid json document is inserted, the JSON_VALID function can be used as a CHECK constraint.
So if you are having issues with the JSON data type in MariaDB, simply just change to LONGTEXT. ;-)
I think you are getting error for JSON datatype.
For Mysql 5.7 you can get help from below link.
https://dev.mysql.com/doc/refman/5.7/en/json.html
You can check vesrion using below query.
select version() as 'mysql version'
"JSON" is parsed in the server. JSON is one of the points of divergence.
MySQL 5.7 introduced the JSON datatype, which matches your syntax.
MariaDB 10.0.16 introduced a ENGINE=CONNECT table_type=JSON which does not match your attempted syntax.
You have given single quotes in your index definitions instead of backticks
Try this:
CREATE TABLE `e_store`.`products`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(250) NOT NULL ,
`brand_id` INT UNSIGNED NOT NULL ,
`category_id` INT UNSIGNED NOT NULL ,
`attributes` JSON NOT NULL ,
PRIMARY KEY(`id`) ,
INDEX `CATEGORY_ID`(`category_id` ASC) , -- Changed single quotes to backticks
INDEX `BRAND_ID`(`brand_id` ASC) , -- Changed single quotes to backticks
CONSTRAINT `brand_id` FOREIGN KEY(`brand_id`) REFERENCES `e_store`.`brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE ,
CONSTRAINT `category_id` FOREIGN KEY(`category_id`) REFERENCES `e_store`.`categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE
);

Dynamically removing records when certain columns = 0; data cleansing

I have a simple card table:
CREATE TABLE `users_individual_cards` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` char(36) NOT NULL,
`individual_card_id` int(11) NOT NULL,
`own` int(10) unsigned NOT NULL,
`want` int(10) unsigned NOT NULL,
`trade` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`,`individual_card_id`),
KEY `user_id_2` (`user_id`),
KEY `individual_card_id` (`individual_card_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
I have ajax to add and remove the records based on OWN, WANT, and TRADE. However, if the user removes all of the OWN, WANT, and TRADE cards, they go to zero but it will leave the record in the database. I would prefer to have the record removed. Is checking after each "update" to see if all the columns = 0 the only way to do this? Or can I set a conditional trigger with something like:
//psuedo sql
AFTER update IF (OWN = 0, WANT = 0, TRADE = 0) DELETE
What is the best way to do this? Can you help with the syntax?
Why not just fire two queries from PHP (or other front end)?
update `users_individual_cards` ...
delete `users_individual_cards` where ... (same condition) and own + want + trade = 0
The trigger will be:
CREATE TRIGGER users_individual_cards_trigger
AFTER UPDATE ON users_individual_cards
FOR EACH ROW
BEGIN
DELETE FROM users_individual_cards
WHERE 'OWN' = 0 AND 'WANT' = 0 AND 'TRADE' = 0;
END$$
The solutions throw the delete query will be better because not all versions of mysql support it.

Why does this MySQL Create Table statement fail?

Using mySQLAdmin tool, I try to create a table. The tool generates the SQL statement, and then replorts a "Can't create table" with no other clue on what error it is!
Here it is :
CREATE TABLE `C121535_vubridge`.`Products` (
`pr_ID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`pr_Name` VARCHAR(45) NOT NULL,
`pr_Type` VARCHAR(2) NOT NULL COMMENT 'H=Hand Series V=VuBridge software E=Event Subs S=Sponsoring',
`pr_AuthorID` INTEGER UNSIGNED COMMENT '= m_ID (for Bridge Hand Series',
`pr_SponsorID` INTEGER UNSIGNED NOT NULL,
`pr_DateCreation` DATETIME NOT NULL,
`pr_Price` FLOAT NOT NULL,
`pr_DescriptionText` TEXT,
`pr_Description` VARCHAR(245),
PRIMARY KEY (`pr_ID`),
CONSTRAINT `FK_prAuthor` FOREIGN KEY `FK_prAuthor` (`pr_AuthorID`)
REFERENCES `Members` (`m_ID`)
ON DELETE SET NULL
ON UPDATE NO ACTION,
CONSTRAINT `FK_Sponsor` FOREIGN KEY `FK_Sponsor` (`pr_SponsorID`)
REFERENCES `Members` (`m_ID`)
ON DELETE SET NULL
ON UPDATE NO ACTION
) ENGINE = InnoDB;
Can someone help?
The CREATE TABLE works for me if I omit the foreign key references:
CREATE TABLE `Products` (
`pr_ID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`pr_Name` VARCHAR(45) NOT NULL,
`pr_Type` VARCHAR(2) NOT NULL COMMENT 'H=Hand Series V=VuBridge software E=Event Subs S=Sponsoring',
`pr_AuthorID` INTEGER UNSIGNED COMMENT '= m_ID (for Bridge Hand Series',
`pr_SponsorID` INTEGER UNSIGNED NOT NULL,
`pr_DateCreation` DATETIME NOT NULL,
`pr_Price` FLOAT NOT NULL,
`pr_DescriptionText` TEXT,
`pr_Description` VARCHAR(245),
PRIMARY KEY (`pr_ID`)
)
...so I'm inclined to believe that C121535_vubridge.MEMBERS does not already exist. C121535_vubridge.MEMBERS needs to be created before the CREATE TABLE statement for the PRODUCTS table is run.
Just split up the create table and try one part at the time. This way you should be able to identify a single line that it fails on.
I do note in the reference manual that if a symbol subclause is given for the CONSTRAINT clause (in your case, the back-quoted strings before FOREIGN KEY in each clause, FK_prAuthor and FK_Sponsor) have to be unique over the database. Are they? If not, that symbol can be omitted and InnoDB will assign then automatically.
Similarly, the tables your FKs refer to may not have the structure that this create statement expects.

MySQL: Error 1628: Comment for table 'customer' is too long (max = 60)

After fixing Error 1253 (MySQL: Unable to fulling forward engineering Sakila (sample) into server), I have Error 1628.
Executing SQL script in server
ERROR: Error 1628: Comment for table 'customer' is too long (max = 60)
Scripts:
CREATE TABLE IF NOT EXISTS `sakila`.`customer` (
`customer_id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT ,
`store_id` TINYINT(3) UNSIGNED NOT NULL ,
`first_name` VARCHAR(45) NOT NULL ,
`last_name` VARCHAR(45) NOT NULL ,
`email` VARCHAR(50) NULL DEFAULT NULL ,
`address_id` SMALLINT(5) UNSIGNED NOT NULL ,
`active` TINYINT(1) NOT NULL DEFAULT TRUE ,
`create_date` DATETIME NOT NULL ,
`last_update` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY (`customer_id`) ,
INDEX `idx_fk_store_id` (`store_id` ASC) ,
INDEX `idx_fk_address_id` (`address_id` ASC) ,
INDEX `idx_last_name` (`last_name` ASC) ,
CONSTRAINT `fk_customer_address`
FOREIGN KEY (`address_id` )
REFERENCES `sakila`.`address` (`address_id` )
ON DELETE RESTRICT
ON UPDATE CASCADE,
CONSTRAINT `fk_customer_store`
FOREIGN KEY (`store_id` )
REFERENCES `sakila`.`store` (`store_id` )
ON DELETE RESTRICT
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT 'Table storing all customers. Holds foreign keys to the address table and the store table where this customer is registered.\n\nBasic information about the customer like first and last name are stored in the table itself. Same for the date the record was created and when the information was last updated.'
SQL script execution finished: statements: 3 succeeded, 1 failed
As an addition: More current versions (5.6.X) allow longer comments. Unfortunately this length differs from the type of comment:
For tables: "A comment for the table, up to 2048 characters long."
For columns: "A comment for a column can be specified with the COMMENT option, up to 1024 characters long."
For INDEX: "In MySQL 5.6, index definitions can include an optional comment of up to 1024 characters."
For PARTITION: "Beginning with MySQL 5.6.6, the maximum length for a partition comment is 1024 characters. (Previously, this limit was not explicitly defined.)"
Source: http://dev.mysql.com/doc/refman/5.6/en/create-table.html
As stated in the MySQL docs, a comment is limited to 255 characters: http://dev.mysql.com/doc/refman/5.1/en/create-table.html#id3411882. Your comment is 305 characters, and it would seem, from the error message, that your particular MySQL install has a 60 character limit.