Create Table and assign a query as default value to a field - mysql

CREATE TABLE `williamhill` (
`id` VARCHAR(50) NULL,
`nick` VARCHAR(50) NULL,
`password` VARCHAR(50) NULL DEFAULT (SELECT default_password FROM person p WHERE p.id = id),
`Colonna 4` VARCHAR(50) NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
How can i do something like that in MYSQL? I'm trying to assign a default value from another table if no value has been specified during the creation of new row.
Is it possible like that or should i use a trigger/procedure?

MySQL is quite explicit that this cannot be done. To begin with, the syntax for default is called default value. A value is expected.
Here is how the documentation describes this:
The DEFAULT value clause in a data type specification indicates a
default value for a column. With one exception, the default value
must be a constant; it cannot be a function or an expression.
(The one exception is CURRENT_TIME which most people probably don't even realize is a function.)
Many databases do allow function calls here. None -- as far as I know -- allow query expressions. However, that can often be emulated in a user-defined function.
The work-around is to use a trigger. Looking up a value in another table is a fairly common use of triggers.

Related

MySql CREATE TABLE and a varchar column with default value of db-function "USER"

With MySql.
There is a way to set a default value.
I know how to do a hard-coded string.
I'm trying to use a
of
USER()
CURRENT_USER
CURRENT_USER()
See 'inserted_by' column below.
If I remove
DEFAULT USER()
it works ok. But that is not what I need.
I've tried all 3 above (after the word DEFAULT). I cannot figure out the magic syntax sugar.
CREATE TABLE `department` (
`department_key` bigint NOT NULL AUTO_INCREMENT,
`name_of` varchar(256) NOT NULL,
`inserted_by` varchar(64) NOT NULL DEFAULT USER(),
`create_date_off_set` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
CONSTRAINT `PK_department` PRIMARY KEY (`department_key`)
)
;
References:
https://dev.mysql.com/doc/refman/8.0/en/built-in-function-reference.html
https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html
"My" Version:
SELECT VERSION();
8.0.23
The default value specified in a DEFAULT clause can be a literal constant or an expression. With one exception, enclose expression default values within parentheses to distinguish them from literal constant default values.
So you want inserted_by varchar(255) NOT NULL DEFAULT (CURRENT_USER())
Unfortunately, MySQL does not allow this.
Default value expression of column 'inserted_by' contains a disallowed function: current_user.
I can't find any reason why it would be disallowed in the documentation, but that's MySQL for you.
Instead, use an insert trigger.
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON department
FOR EACH ROW
SET new.inserted_by = COALESCE(new.inserted_by, current_user())

MySQL: Expression of generated column contains disallowed function? CONCAT?

I have a table with a virtual generated column that concatenates five other columns (int and char) using CONCAT_WS(). This table contains 200-odd records and is never updated - it's just used as a lookup table. Recently, after months of untroubled processing, when I update records in a child table during which a SELECT is performed on this table, I sometimes see this error (ignore the "ITEM UPDATE FAILED" - that's me):
I am in development with a many changes every day, so it is impossible for me to determine if there is a correlating change. I have recently added "created" and "lastmodified" datetime fields to several tables with CURRENT_TIMESTAMP for DEFAULT or ON UPDATE, but not to this table.
Here's the table:
{EDIT} --- adding table definition:
CREATE TABLE `cpct_fixedfield` (
`id` int(11) UNSIGNED NOT NULL,
`name` varchar(256) NOT NULL,
`label` varchar(50) NOT NULL,
`field` int(11) NOT NULL,
`start` int(11) NOT NULL,
`rectype` int(11) NOT NULL ,
`mediatype` char(1) NOT NULL DEFAULT '' ,
`length` int(11) NOT NULL,
`userdefined` tinyint(1) NOT NULL,
`defaultval` varchar(5) NOT NULL,
`helpcode` varchar(10) NOT NULL,
`mandatory` varchar(2) NOT NULL ,
`idx` varchar(20) GENERATED ALWAYS AS (concat_ws('.',`field`,`rectype`,`mediatype`,`start`,`length`)) VIRTUAL NOT NULL)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
The length of the data in field never exceeds 11chars. I can view the entire table in pma or Mysql Workbench and the virtual field materialises in all records without complaint, which suggests to me that there is nothing wrong with either the expression for the virtual column or the data in the columns that expression draws on.
The error occurs in several contexts when I am updating a child table. All the updates occur in Stored Procedures/Functions. One section of code that seems to trigger the error is this:
SET idxvar = CONCAT_WS(".", SUBSTRING(tmpfldkey,3,1), rectype, ptype, position, "%") COLLATE utf8mb4_general_ci;
SELECT id INTO ffid FROM cpct_fixedfield WHERE idx LIKE idxvar AND idx != "0.0..6.2";
All the variables involved are varchars or ints. utf8mb4_general_ci is used throughout the database.
I cannot find any reference in MYSQL documentation to CONCAT or CONCAT_WS being unsafe, and none of the columns referenced has a default using a non-deterministic function. All the other questions I can find in this forum and elsewhere about this error have arisen because of the use of non-deterministic functions like CURRENT_TIMESTAMP() in the virtual field, or a component of the field.
I replaced the SELECT on the table with a (large) CASE statement and all was well, and in fact, after I did this then reverted to the SELECT I had no errors for many hours. But it just happened again (so I'm back to the case statement).
I have run out of ideas - I'm hoping someone has some knowledge/experience that can help.
Thanks

Why this MySQL IN takes so much longer than WHERE OR?

I have two tables, identities and events.
identities has only two columns, identity1 and identity2 and both have a HASH INDEX.
events has ~50 columns and the column _p has a HASH INDEX.
CREATE TABLE `identities` (
`identity1` varchar(255) NOT NULL DEFAULT '',
`identity2` varchar(255) DEFAULT NULL,
UNIQUE KEY `uniques` (`identity1`,`identity2`),
KEY `index2` (`identity2`) USING HASH,
KEY `index1` (`identity1`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
CREATE TABLE `events` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`_p` varchar(255) NOT NULL,
`_t` int(10) NOT NULL,
`_n` varchar(255) DEFAULT '',
`returning` varchar(255) DEFAULT NULL,
`referrer` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
[...]
`fcc_already_sells_online` varchar(255) DEFAULT NULL,
UNIQUE KEY `_p` (`_p`,`_t`,`_n`),
KEY `rowid` (`rowid`),
KEY `IDX_P` (`_p`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=5231165 DEFAULT CHARSET=utf8;
So, why does this query:
SELECT SQL_NO_CACHE * FROM events WHERE _p IN (SELECT identity2 FROM identities WHERE identity1 = 'user#example.com') ORDER BY _t
takes ~40 seconds, while this one:
SELECT SQL_NO_CACHE * FROM events WHERE _p = 'user#example.com' OR _p = 'user2#example.com' OR _p = 'user3#example.com' OR _p = 'user4#example.com' ORDER BY _t
takes only 20ms when they are basically the same?
edit:
This inner query takes 3,3ms:
SELECT SQL_NO_CACHE identity2 FROM identities WHERE identity1 = 'user#example.com'
The cause:
MySQL treats conditions IN <static values list> and IN <sub-query> as different things. It is well-stated in documentation that the second one is equal to = ANY() query which can not use index even if that index exists. MySQL is just not ingenious enough to do it. On the opposite, first one is treated as a simple range scan when the index is there meaning that MySQL can easily use the index.
Possible ways to resolve:
As I see it, there are workarounds and you've already even mentioned one of them. So it may be:
Using JOIN. If there is a field to join by, this is most likely the best way to solve a problem. Actually, since version 5.6 MySQL already tries to enforce this optimization if it's possible, but that does not work in complex cases or in case where there is no dependent sub-query (so basically if MySQL can not "track" that reference). Looking to your case, this isn't an option and this is actually what is not happening for your sub-query.
Querying the sub-resource in the application and forming the static list. Yes, despite the common practice is to avoid multiple queries due to connection/network/query planning overhead, this is the case where actually it can work. In your case, even if you have something like 200ms overhead on all the recounted stuff before, it still worth to query sub-resource independently and substitute static list to next query in the application afterwards.
this is already asked
it's easier to to manage the IN operator because is only a construct that defines the OR operator on multiple conditions with = operator on the same value. If you use the OR operator the optimizer may not consider that you're always using the = operator on the same value.
Because your query is calling this inner query for each row in events table.
In second case indentity table is not used.
You should use joining instead.

Getting Default value N'no' is not supported for VARCHAR(3) NULL DEFAULT 'no'

I'm using the MySQL Workbench 6.0 tool to migrating data from a MS SQL Server 2000 database to a MySQL 5.6 database and many of the create table constructs are giving the error "Default value N'no' is not supported" on columns that allow null, but define a default value. Here is some example code where the complaint is on the definition of the distribution column definition.
The Table construct looks like this:
CREATE TABLE IF NOT EXISTS `dbo`.`_tbl_access` (
`distribution` VARCHAR(3) NULL DEFAULT 'no',
`email` VARCHAR(100) NULL)
The idea is that you can store NULL, but have the default be 'no'. Is this a known problem to allow NULL, but to store a value of 'no' as default?
As stated in the MySLQ 5.6 documentation, you can't use your own default value on a column which can take NULL as a value:
If the column can take NULL as a value, the column is defined with an explicit DEFAULT NULL clause.
11.5. Data Type Default Values
If you want exactly the same behavior, you can use custom triggers. You may also consider redesigning the database, e.g. to ask yourself if a record should exist in the '_tbl_access' table if the answer for the 'distribution' field is undefined (NULL).

how to set a defaut using function uuid() in mysql?

I want to set a uuid value to "id" field via function uuid().
And I do not want to use as Trigger.
CREATE TABLE `test` (
`id` VARCHAR(36) NOT NULL DEFAULT uuid(),
`username` VARCHAR(250) NULL DEFAULT NULL,
`values` VARCHAR(250) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB;
the spec is quite explicit on this: http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html
With one exception, the default value must be a constant; it cannot be a function or an expression. This means, for example, that you cannot set the default for a date column to be the value of a function such as NOW() or CURRENT_DATE. The exception is that you can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP column.
so either you use triggers, calculate the value beforehand (e.g. in php) or you use some other database, e.g. oracle might support it.