Why does PopSQL ask me to check the manual? - mysql

I'm currently learning SQL using the popsql ide. I'm trying to run the command to create a table but I keep gettting
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '--auto increment automatically adds 1 to the primary key-- name VARCHAR(20) ' at line 2
What am I doing wrong? Below is the sql code
--writing table in all caps differentiates it from other phrases
--the keyword phrase NOT NULL indicates that the column has to have a value in it at every row
--the UNIQUE keyphrase indicates that the column values have to be unique
CREATE TABLE student (
student_id INT AUTO_INCREMENT,--auto increment automatically adds 1 to the primary key
name VARCHAR(20) NOT NULL,
major VARCHAR (20) UNIQUE,
age INT DEFAULT 'undecided', --the DEFAULT keyword will populate a particular row with phrase in quotes if there is no info entered
PRIMARY KEY(student_id)
);
--constraints are rules that we set in our db to control what happens to info.
--creating a rule such that a particular keyword should populate a row when no data is in it is a constraint
DESCRIBE student;
--the keyword 'DROP' deletes any item that we specify--
DROP TABLE student;
--THIS LINE ADDS THE GPA COLUMN TO OUR TABLE--
ALTER TABLE student ADD gpa DECIMAL(3,2);
--this command displays the info that's currently in the table
SELECT * FROM student;
--INSERTING DATA INTO THE TABLE
--the order in which the tables were created should be the order in whcich they should be inserted into the table
--INSERT INTO student VALUES (2,'Rose', 'Chemistry',3.23);
--you can specify what values to add to the database if you don't have a particular key
INSERT INTO student(name, major) VALUES('John', 'Chemistry');

The error message is correct: you should consult the manual when you are in doubt.
From the MySQL documentation on comments:
From a -- sequence to the end of the line. In MySQL, the -- (double-dash) comment style requires the second dash to be followed by at least one whitespace or control character (such as a space, tab, newline, and so on). This syntax differs slightly from standard SQL comment syntax, as discussed in Section 1.7.2.4, “'--' as the Start of a Comment”.
You did not do that, so your syntax is invalid.

Related

MySQL - Concatenate Existing Fields in New Generated Field

In my table, I have two fields: book and reference. Neither are required to be unique on their own. However, the concatenated value of these two values must be unique.
I'm trying to create a generated column that concatenates the two, but I'm receiving the following error message when running the SQL:
Executing:
ALTER TABLE `bibleverses`.`myverses`
ADD COLUMN `fullref` VARCHAR(20) GENERATED ALWAYS AS (CONCAT(book, reference)) STORED AFTER `mp3`;
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GENERATED ALWAYS AS (CONCAT(book, reference)) STORED AFTER `mp3`' at line 2
SQL Statement:
ALTER TABLE `bibleverses`.`myverses`
ADD COLUMN `fullref` VARCHAR(20) GENERATED ALWAYS AS (CONCAT(book, reference)) STORED AFTER `mp3`
You can achieve this thing by just applying UNIQUE key constraint to both these columns and it will become a composite key so that you can store the unique values in a pair of these two columns. You can try following SQL statement :
ALTER TABLE bibleverses.myverses ADD UNIQUE(book, reference);
First execute an alter table to add your new column, then you run an update to fill out the fild, like:
ALTER TABLE <table_name> ADD COLUMN <column name, type, definition, etc>;
UPDATE TABLE <table_name> SET <field> = <value>;
To create a virtual generated column (which updates if the constituents changes)
ALTER TABLE producerADD COLUMNFullName varchar(32) as (CONCAT(FirstName,' ',Surname));

Field containing numbers and letters [duplicate]

Suppose I have an attribute called phone number and I would like to enforce certain validity on the entries to this field. Can I use regular expression for this purpose, since Regular Expression is very flexible at defining constraints.
Yes, you can. MySQL supports regex (http://dev.mysql.com/doc/refman/5.6/en/regexp.html) and for data validation you should use a trigger since MySQL doesn't support CHECK constraint (you can always move to PostgreSQL as an alternative:). NB! Be aware that even though MySQL does have CHECK constraint construct, unfortunately MySQL (so far 5.6) does not validate data against check constraints. According to http://dev.mysql.com/doc/refman/5.6/en/create-table.html: "The CHECK clause is parsed but ignored by all storage engines."
You can add a check constraint for a column phone:
CREATE TABLE data (
phone varchar(100)
);
DELIMITER $$
CREATE TRIGGER trig_phone_check BEFORE INSERT ON data
FOR EACH ROW
BEGIN
IF (NEW.phone REGEXP '^(\\+?[0-9]{1,4}-)?[0-9]{3,10}$' ) = 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Wroooong!!!';
END IF;
END$$
DELIMITER ;
INSERT INTO data VALUES ('+64-221221442'); -- should be OK
INSERT INTO data VALUES ('+64-22122 WRONG 1442'); -- will fail with the error: #1644 - Wroooong!!!
However you should not rely merely on MySQL (data layer in your case) for data validation. The data should be validated on all levels of your app.
MySQL 8.0.16 (2019-04-25) and MariaDB 10.2.1 (2016-04-18) now not only parse CHECK constraint but also enforces it.
MySQL: https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html
MariaDB: https://mariadb.com/kb/en/constraint/
Actually, we can can set regular expression within check constraints in MySQL.
Eg.,:
create table fk
(
empid int not null unique,
age int check(age between 18 and 60),
email varchar(20) default 'N/A',
secondary_email varchar(20) check(secondary_email RLIKE'^[a-zA-Z]#[a-zA-Z0-9]\.[a-z,A-Z]{2,4}'),
deptid int check(deptid in(10,20,30))
)
;
This INSERT query will work:
insert into fk values(1,19,'a#a.com','a#b.com', 30);
This INSERT query will not work:
insert into fk values(2,19,'a#a.com','a#bc.com', 30);

How to check a string while entering it in MySQL DB for characters in the beginning by DEFAULT?

I want to create a table where i want to list some books on different subject. I want to include first letter of the topic in the book id. For example, books on mathematics will contain 'M', literature will contain 'C'.
I had the idea to use something like
CREATE TABLE book (id VARCHAR(5) DEFAULT LIKE 'M%', book_name VARCHAR(10))
But, it's showing error.
Static analysis:
2 errors were found during analysis.
A comma or a closing bracket was expected. (near "'M%'" at position
46)
Blockquote
Unexpected beginning of statement. (near "10" at position 71)
SQL query:
CREATE TABLE book (id VARCHAR(5) DEFAULT LIKE 'M%', book_name VARCHAR(10))
MySQL said: Documentation
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 'LIKE 'M%', book_name VARCHAR(10))' at line 1
The query usage of default is wrong. You can have only fixed text in default.
Also I am not sure if you want text ending with M in ID or book_name, but looking at the query I am assuming it is id.
You need to use constraint to control the values allowed for id. Correct query with constraint will be as below
CREATE TABLE book (id VARCHAR(5), book_name VARCHAR(10), CONSTRAINT check_book_name CHECK (id like '%M'))
Next thing is
I want to include first letter of the topic in the book id.
to do that you can only add constraint as check but you can control this only through your insert statement.
My suggestion formulate the data set. Then simply create table. Based on your dataset add constraint on the table. Add pre-insert validations. This pre-insert validation would be along with the app or code executing the insert statement.

OUTPUT Inserted.row in mysqli

I have the following sql table:
id|email|fbid
When I perform the query
INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue')
I want to get the id of the inserted row. To do so, I've tried to edit the query like this:
INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue') OUTPUT Inserted.id
But I'm getting:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'OUTPUT Inserted.id' at line 1
What could be the problem?
Unfortunately (as far as I can tell) mysql does not support output as sql-server does.
You do have an option for what you're trying to accomplish in a single row insert (assuming auto_increment primary key):
SELECT LAST_INSERT_ID();
This unfortunately would not work in the case of a batch insert - though in your case you are not (at least not in your example), so this should be fine.
I'm going to use the process i describe below to handle the same situation with a private at home (non-enterprise) application that i wrote for personal use. I know this question is a year old right now but there doesn't seem to be an adequate answer for batch processing. I can't find an adequate answer. MySQL doesn't seem to have the facilities built into it to handle this type of thing.
I had concerns about the reliability of this solution, when put into a production environment where multiple different users/jobs could access the same procedure at the same time to do the insert. I believe I have resolved these concerns by adding the connection id to the #by variable assignment. Doing this makes it so that the by has a: the connection id for the session and b: the name of the program/job/procedure doing the insert. Combined with the date AND time of the insert, I believe these three values provide a very secure key to retrieve the correct set of inserted rows. If absolute certainty is required for this, you could possibly add a third column of a GUID type (or varchar) generate a GUID variable to insert into that, then use the GUID variable along with #by and #now as your key. I feel it's unnecessary for my purpose because the process I'm going to use it in is an event (job) script that runs on the server rather than in PHP. So I am not going to exemplify it unless someone asks for that.
WARNING
If you are doing this in PHP, consider using a GUID column in your process rather than the CreatedBy. It's important that you do that in PHP because your connection can be lost in between inserting the records and trying to retrive the IDS and your CreatedBy with the connection ID will be rendered useless. If you have a GUID that you create in PHP, however, you can loop until your connection succeeds or recover using the GUID that you saved off somewhere in a file. The need for this level of connection security is not necessary for my purposes so I will not be doing this.
The key to this solution is that CreatedBy is the connection id combined with the name of the job or procedure that is doing the insert and CreatedDate is a CURRENT_TIMESTAMP that is held inside a variable that is used through the below code. Let's say you have a table named "TestTable". It has the following structure:
Test "Insert Into" table
CREATE TABLE TestTable (
TestTableID INT NOT NULL AUTO_INCREMENT
, Name VARCHAR(100) NOT NULL
, CreatedBy VARCHAR(50) NOT NULL
, CreatedDate DATETIME NOT NULL
, PRIMARY KEY (TestTableID)
);
Temp table to store inserted ids
This temporary table will hold the primary key ids of the rows inserted into TestTable. It has a simple structure of just one field that is both the primary key of the temp table and the primary key of the inserted table (TestTable)
DROP TEMPORARY TABLE IF EXISTS tTestTablesInserted;
CREATE TEMPORARY TABLE tTestTablesInserted(
TestTableID INT NOT NULL
, PRIMARY KEY (TestTableID)
);
Variables
This is important. You need to store the CreatedBy and CreatedDate in a variable. CreatedBy is stored for consistency/coding practices, CreatedDate is very important because you are going to use this as a key to retrieve the inserted rows.
An example of what #by will look like: CONID(576) BuildTestTableData
Note that it's important to encapsulate the connection id with something that indicates what it is since it's being used as a "composite" with other information in one field
An example of what #now will look like: '2016-03-11 09:51:10'
Note that it's important to encapsulate #by with a LEFT(50) to avoid tripping a truncation error upon insert into the CreatedBy VARCHAR(50) column. I know this happens in sql server, not so sure about mysql. If mysql does not throw an exception when truncating data, a silent error could persist where you insert a truncated value into the field and then matches for the retrieval fail because you're trying to match a non-truncated version of the string to a truncated version of the string. If mysql doesn't truncate upon insert (i.e. it does not enforce type value restrictions) then this is not a real concern. I do it out of standard practice from my sql server experience.
SET #by = LEFT(CONCAT('CONID(', CONNECTION_ID(), ') BuildTestTableData'), 50);
SET #now = CURRENT_TIMESTAMP;
Insert into TestTable
Do your insert into test table, specifying a CreatedBy and CreatedDate of #by and #now
INSERT INTO TestTable (
Name
, CreatedBy
, CreatedDate
)
SELECT Name
, #by
, #now
FROM SomeDataSource
WHERE BusinessRulesMatch = 1
;
Retrieve inserted ids
Now, use #by and #now to retrieve the ids of the inserted rows in test table
INSERT INTO tTestTablesInserted (TestTableID)
SELECT TestTableID
FROM TestTable
WHERE CreatedBy = #by
AND CreatedDate = #now
;
Do whatever with retreived information
/*DO SOME STUFF HERE*/
SELECT *
FROM tTestTablesInserted tti
JOIN TestTable tt
ON tt.TestTableID = tti.TestTableID
;
if You are using php then it is better to use following code :
if ($conn->query($sql) === TRUE) {
$last_id = $conn->insert_id;
echo "New record created successfully. Last inserted ID is: " . $last_id;
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
where $conn is connection variable.

Is it Possible to Enforce Data Checking in MySQL using Regular expression

Suppose I have an attribute called phone number and I would like to enforce certain validity on the entries to this field. Can I use regular expression for this purpose, since Regular Expression is very flexible at defining constraints.
Yes, you can. MySQL supports regex (http://dev.mysql.com/doc/refman/5.6/en/regexp.html) and for data validation you should use a trigger since MySQL doesn't support CHECK constraint (you can always move to PostgreSQL as an alternative:). NB! Be aware that even though MySQL does have CHECK constraint construct, unfortunately MySQL (so far 5.6) does not validate data against check constraints. According to http://dev.mysql.com/doc/refman/5.6/en/create-table.html: "The CHECK clause is parsed but ignored by all storage engines."
You can add a check constraint for a column phone:
CREATE TABLE data (
phone varchar(100)
);
DELIMITER $$
CREATE TRIGGER trig_phone_check BEFORE INSERT ON data
FOR EACH ROW
BEGIN
IF (NEW.phone REGEXP '^(\\+?[0-9]{1,4}-)?[0-9]{3,10}$' ) = 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Wroooong!!!';
END IF;
END$$
DELIMITER ;
INSERT INTO data VALUES ('+64-221221442'); -- should be OK
INSERT INTO data VALUES ('+64-22122 WRONG 1442'); -- will fail with the error: #1644 - Wroooong!!!
However you should not rely merely on MySQL (data layer in your case) for data validation. The data should be validated on all levels of your app.
MySQL 8.0.16 (2019-04-25) and MariaDB 10.2.1 (2016-04-18) now not only parse CHECK constraint but also enforces it.
MySQL: https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html
MariaDB: https://mariadb.com/kb/en/constraint/
Actually, we can can set regular expression within check constraints in MySQL.
Eg.,:
create table fk
(
empid int not null unique,
age int check(age between 18 and 60),
email varchar(20) default 'N/A',
secondary_email varchar(20) check(secondary_email RLIKE'^[a-zA-Z]#[a-zA-Z0-9]\.[a-z,A-Z]{2,4}'),
deptid int check(deptid in(10,20,30))
)
;
This INSERT query will work:
insert into fk values(1,19,'a#a.com','a#b.com', 30);
This INSERT query will not work:
insert into fk values(2,19,'a#a.com','a#bc.com', 30);