I'm using MySQL Workbench and I made a table called 'organizations' and want to block any try of adding a value to a column with less than 5 letters.
The column name is 'namee'.
I made this, but I get an error:
ALTER TABLE organizations
ADD CONSTRAINT MINIMO CHECK (LENGTH(namee) >= 5);
Error:
Error Code: 3814. An expression of a check constraint 'MINIMO' contains disallowed function: `LEN`.
Based on the error message you shared, you apparently tried to use a function LEN(). No built-in function of that name exists in MySQL.
Testing with MySQL 8.0.21, I can reproduce the error you showed if I try using LEN() or any other nonexistent function.
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+
1 row in set (0.00 sec)
mysql> ALTER TABLE organizations ADD CONSTRAINT MINIMO CHECK (LEN(namee) >= 5);
ERROR 3814 (HY000): An expression of a check constraint 'MINIMO' contains disallowed function: `LEN`.
mysql> ALTER TABLE organizations ADD CONSTRAINT MINIMO CHECK (BOGUS(namee) >= 5);
ERROR 3814 (HY000): An expression of a check constraint 'MINIMO' contains disallowed function: `BOGUS`.
If you had tried to define a stored function called LEN() and use that, you should read https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html:
Stored functions and user-defined functions are not permitted.
But LENGTH() works without error. By the way, I'd recommend to use CHAR_LENGTH() so multibyte characters are counted as one character.
mysql> ALTER TABLE organizations ADD CONSTRAINT MINIMO CHECK (CHAR_LENGTH(namee) >= 5);
Query OK, 1 row affected (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 0
That seems odd. Does this work?
ALTER TABLE organizations
ADD CONSTRAINT MINIMO CHECK (LENGTH(namee) LIKE '_____');
I suspect that LENGTH() is non-deterministic; I am not sure why this would be.
At least in older versions, and you didn't specify which version, a trigger is needed for checking length.
CREATE TRIGGER t1 BEFORE INSERT ON organizations
FOR EACH ROW BEGIN
DECLARE numLength INT;
SET numLength = (SELECT LENGTH(NEW. namee));
IF (numLength > 30) THEN
SET NEW.col = 1/0;
END IF;
END;
Consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (my_string VARCHAR(20) NOT NULL);
SET #string = 'red';
INSERT INTO my_table SELECT #string FROM (SELECT 1)x WHERE CHAR_LENGTH(#string) >= 5;
SET #string = 'orange';
INSERT INTO my_table SELECT #string FROM (SELECT 1)x WHERE CHAR_LENGTH(#string) >= 5;
SELECT * FROM my_table;
+-----------+
| my_string |
+-----------+
| orange |
+-----------+
I am not sure which version you are using but it works fine for me on MYSQL 8.x
create table test_check(name varchar(10));
ALTER TABLE test_check
ADD CONSTRAINT MINIMO CHECK (LENGTH(name) >= 5);
Related
Let's say I have two BEFORE UPDATE triggers on the same table. We'll call them trigger A and trigger B. Order is enforced, so A will always be executed first, and B will always be executed second.
Will OLD and NEW reference the same values in the body of both A and B?
Or will the NEW values of A become the OLD values of B? Meaning B is referencing a new UPDATE statement, which is a product of A?
The OLD values reference the row before the UPDATE. That is, before any of the triggers execute. These never change during the triggers.
The NEW values reference the row with values you mean to change.
One trigger may modifies the NEW values. Then the subsequent trigger will see the modified values, still in the NEW row.
Demo:
mysql> create table mytable (id serial primary key, x int);
mysql> insert into mytable set x = 1;
mysql> delimiter $$
mysql> create trigger t1 before update on mytable
for each row begin set NEW.x = NEW.x + 1; end$$
mysql> create trigger t2 before update on mytable
for each row follows t1 begin set #x_old = OLD.x; set #x_new = NEW.x; end$$
mysql> delimiter ;
mysql> update mytable set x = 10;
mysql> select #x_old, #x_new;
+--------+--------+
| #x_old | #x_new |
+--------+--------+
| 1 | 11 |
+--------+--------+
I have this query in MySQL database 8.0.12 version
mysql> SELECT tTbl INTO #tTbl FROM t_table WHERE tTbl = "t_contents_1_2021";
SELECT #tTbl;
Query OK, 1 row affected (0.07 sec)
+-------------------+
| #tTbl |
+-------------------+
| t_contents_1_2021 |
+-------------------+
1 row in set (0.07 sec)
Now I need test whether a row exists in a MySQL table or not, using exists condition.
The exists condition can be used with subquery.
It returns true when row exists in the table, otherwise false is returned. True is represented in the form of 1 and false is represented as 0.
I have tried without success
mysql> SELECT EXISTS(SELECT tTbl INTO #tTbl FROM t_table
WHERE tTbl = "t_contents_1_2021");
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 '(SELECT tTbl INTO #tTbl FROM t_table
WHERE tTbl' at line 1
mysql>
How to do resolve this?
SELECT .. INTO does not return the rowset. EXISTS needs in rowset. So SELECT .. INTO cannot be used in EXISTS.
Remove it:
SELECT EXISTS ( SELECT tTbl
FROM t_table
WHERE tTbl = "t_contents_1_2021" );
If you need both check the row existence and save the value to the variable then use inline assigning:
SELECT EXISTS ( SELECT NULL
FROM t_table
WHERE (#tTbl := tTbl) = "t_contents_1_2021" );
I am having difficult getting a procedure to update a table in the way I require. I am using phpmyadmin on my local computer. In phpmyadmin I can put the following code into the SQL tab and one row will be updated:
SET `adjCost` = 22.05 WHERE `Name` LIKE CONCAT('magic', '%') AND `idKey` = '2016fulham02345';
As expected and wanted, IF the name begins with magic AND the idKey is '2016fulham02345' THEN the adjCost is updated to 22.05.
There will be between 2 and 50 rows with the same idKey. The Name will never be repeated in a set with the same idKey.
I created a procedure with the following parameters:
IN idK VARCHAR 255 Charset
IN aName VARCHAR 255 Charset
IN cost FLOAT 5,2
BEGIN
UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` LIKE CONCAT(aName, '%') AND `idKey` = idK;
END
When I run this procedure it updates ALL adjCost where the idKey = idk and (seems) to ignore the name parameter.
I have tried concatenating the name string first:
BEGIN
SELECT CONCAT(aName, '%') INTO #str;
UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` = #str AND `idKey` = idK;
END
but to no avail.
I looked through w3schools, stackoverflow and google and have not been able to find the answer.
My question is:
How can I correct my procedure to get it to work as I would like?
UPDATE: as requested.
CREATE DEFINER=`root`#`localhost` PROCEDURE `importAltUpdateAjdCost`(IN `idK` VARCHAR(255), IN `aName` VARCHAR(255), IN `cost` FLOAT(5,2))
NO SQL
BEGIN
UPDATE `costingPP`
SET `adjCost` = cost
WHERE
`Name` LIKE CONCAT(aName, '%')
AND
`idKey` = idK;
END
To get this, I selected export on my list of procedures on phpmyadmin.
I'm not entirely sure what or how you did, but here's what I did and it instantly worked. Since you didn't specify MySQL version, I used 5.7.
EDIT: Now as I went back to see your procedure creation statement I realised that NO SQL was introduced in MySQL 8.0. Since your procedure clearly is SQL then please remove the NO SQL and re-create the procedure.
I'm leaving my MySQL 5.7 sample here for reference:
1) Created a simple table:
mysql> CREATE TABLE raceresults (
-> idKey VARCHAR(255),
-> Name VARCHAR(255),
-> adjCost FLOAT(5,2)
-> );
Query OK, 0 rows affected (0.06 sec)
2) Here we insert a sample data row:
mysql> INSERT INTO raceresults VALUES ('2016fulham02345', 'magicFlyingHorse', 0.00);
Query OK, 1 row affected (0.01 sec)
3) To create a (STORED) PROCEDURE we have to temporarily set a different delimiter, so query parser wouldn't terminate procedure creation on default semi-colon, as it's used inside the procedure. After delimiter's change we create the procedure and set the delimiter back to semi-colon
mysql> DELIMITER //
mysql> CREATE PROCEDURE update_test(IN idK VARCHAR(255), IN aName VARCHAR(255), IN cost FLOAT(5,2))
-> BEGIN
-> UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` LIKE CONCAT(aName, '%') AND `idKey` = idK;
-> END//
mysql> DELIMITER ;
Query OK, 0 rows affected (0.00 sec)
4) Now let's see how it all works. Before and after the procedure call I'm selecting the rows from database. You can see the cost column value changing:
mysql> SELECT * FROM raceresults;
+-----------------+------------------+---------+
| idKey | Name | adjCost |
+-----------------+------------------+---------+
| 2016fulham02345 | magicFlyingHorse | 0.00 |
+-----------------+------------------+---------+
1 row in set (0.00 sec)
mysql> CALL update_test('2016fulham02345', 'magic', 1.23);
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM raceresults;
+-----------------+------------------+---------+
| idKey | Name | adjCost |
+-----------------+------------------+---------+
| 2016fulham02345 | magicFlyingHorse | 1.23 |
+-----------------+------------------+---------+
1 row in set (0.00 sec)
And now one piece of advise too:
If possible, use only lower case table, column, indexes, functions, procedures, etc... names, while always writing all SQL commands in uppercase (which you did). This is kind of a de facto standard and makes life easier both for you and others reading your code.
hello I have a datetime column and I would like to put a time restriction on it how would I do this?
For example a range of time from 3:00:00 to 15:00:00 all data that fits this criteria is stored if not throw and error up and stop the entering of data in the column
In MySQL, you'd have to do this with a trigger on INSERT and UPDATE, so if someone tries to enter a value that doesn't meet your criteria, you raise a SIGNAL.
mysql> CREATE TABLE MyTable (
my_datetime DATETIME
);
mysql> DELIMITER ;;
mysql> CREATE TRIGGER MyTable_ins BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
IF (NOT TIME(NEW.my_datetime) BETWEEN '03:00:00' AND '15:00:00') THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Time does not fall in the range allowed.'
END IF;
END;;
mysql> DELIMITER ;
I get the error if try to do something I shouldn't:
mysql> INSERT INTO MyTable SET my_datetime = '2017-01-13 18:00:00';
ERROR 1644 (45000): time does not fall in the range allowed
But it works if I choose a time that's allowed:
mysql> INSERT INTO MyTable SET my_datetime = '2017-01-13 11:00:00';
Query OK, 1 row affected (0.00 sec)
I did some digging and some reading. I tested some stuff out on my own server. It doesn't work. Then I found this answer:
CHECK constraint in MySQL is not working
Yep, it accepts a CHECK constraint as valid syntax, then completely ignores it.
And while I was testing and writing up, Bill has posted the correct answer for MySQL. Do what he says.
I want to do the following query:
UPDATE `users` SET balance = (balance - 10) WHERE id=1
But if the balance will become a negative number I want an error to be returned. Any ideas on if this is possible?
If you do
UPDATE `users` SET balance = (balance - 10) WHERE id=1 and balance >=10
You should be able to detect that a row was not modified.
Note that while another answer suggests using an unsigned int column, this may not work:
Create a test table
create table foo(val int unsigned default '0');
insert into foo(val) values(5);
Now we attempt to subtract 10 from our test row:
update foo set val=val-10;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 1
mysql> select * from foo;
+------------+
| val |
+------------+
| 4294967295 |
+------------+
This was on mysql 5.0.38
You can make the balance field of the users table an unsigned int:
ALTER TABLE `users` CHANGE `balance` `balance` INT UNSIGNED;
This sort of things is done by triggers. MySql have support for triggers only since 5.0.2.
DELIMITER $$
CREATE TRIGGER balance_check BEFORE INSERT ON user FOR EACH ROW
BEGIN
IF new.balance < #limit_value THEN
-- do something that causes error.
-- mysql doesn't have mechanism to block action by itself
END IF;
END $$
DELIMITER ;
Triggers in MySql are quite rudimentary. You have to hack things around to do some things (e.g. cause error).
I dont think you can do this with a simple query. you should use a mysql user defined function that manage that before update the row. or a trigger
Just a tip that wouldn't fit as a comment. I was just trying to subtract 32000 from 32047 (not a negative result) and was getting errors. Also confusing, I was getting BIGINT errors but my subtraction was on a SMALLINT column! (Which still makes no sense.)
If you're getting "out of range" errors even when your "balance" is positive, try adding "limit 1" to the end of your query. Maybe this is a bug in MySQL?
mysql> update posts set cat_id=cat_id-32000 where timestamp=1360870280;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`xxxxx`.`posts`.`cat_id` - 32000)'
mysql> update posts set cat_id=cat_id-32000 where timestamp=1360870280 limit 1;
Query OK, 1 row affected (6.45 sec)
Rows matched: 1 Changed: 1 Warnings: 0
In my case the timestamp is unique (I just checked to be sure) but not explicitly defined as unique when I created the table. So why is the "limit 1" here necessary? But who cares, it works!