I have a tableA with following output from desc tableA command:
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | | |
| city | varchar(50) | YES | | NULL | |
| state | char(2) | YES | | NULL | |
| country | varchar(30) | YES | | NULL | |
| notes | longtext | YES | | NULL | |
| type | varchar(50) | NO | | NULL | |
+---------+-------------+------+-----+---------+----------------+
Now there are 3 columns with NOT NULL constraints:
id
name
type
For columns id and type, I need to remove the default constraint. Basically I want Default: None. I do not want to use the workarounds eg . setting default to '' for a varchar.
The difference between NULL, NONE, and '' is made more clear from this discussion Default-values-for-varchar-and-int-mysql-data-types
I tried using the command:
alter table tableA alter column type drop default;
The query runs fine, but no rows are affected. And no change in Default value is shown when I run describe command.
If I set the default value to '' I run into different issue - the database allows the entry of empty string in the db. For me that is equivalent to inserting NULL for a column's value, and I do not want to allow that.
I need some guidance on how to handle Default values in this situation where I cannot allow empty strings as data in the db. I want to mention that I am planning to put validations in the code to check if the incoming data is an empty string or NULL. But just in case that validation is not working etc, I want to make sure the DB can refuse to add such data.
Any help is really appreciated.
If the column can be then null, then either default or null are the same.
So Allowed Null, Default null is effectively irrelevant except when doing say
Insert (name,city,type) Values ('Fred',DEFAULT,'Caucasian')
Null isn't an empty string. Given you are allowing null in the table but interpreting it as empty string in your application, you have an irritating flaw in your design.
If you don't want empty strings in there, normally you'd use a check constraint which as far as I know still isn't implemented in mysql. Apparently this lack is usually solved with an insert trigger.
So you'd check the value in the trigger and then fail the insert for empty strings.
PS it doesn't solve the integrity problem, but if you did want a way to put nulls in when a straing was empty so you would not have to distinguish between empty string and null.
Then have a look at the nullif function.
Related
Is there a way to change te value of the Extra column that is shown with the SHOW COLUMNS/DESCRIBE sentences?
The documentation about this column states the following:
Extra
Any additional information that is available about a given column. The
value is nonempty in these cases:
auto_increment for columns that have the AUTO_INCREMENT attribute.
on update CURRENT_TIMESTAMP for TIMESTAMP or DATETIME columns that
have the ON UPDATE CURRENT_TIMESTAMP attribute.
VIRTUAL GENERATED or VIRTUAL STORED for generated columns.
DEFAULT_GENERATED for columns that have an expression default value.
I have the next table columns information but I wish to remove the Extra value of the start_date column.
Is there a way to do this?
+--------------------+--------------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------------+------+-----+-------------------+-------------------+
| id_machine_product | "int(10) unsigned" | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
| start_date | timestamp | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+--------------------+--------------------+------+-----+-------------------+-------------------+
EDIT:
I have implemented a fingerprint validation method in PHP that diffs the DESCRIBE tables values, I have database versions in production that doesn't have that Extra value even though those columns have an expression default value, so currently, I wish to alter that value so I don't get errors from my implemented fingerprint validation method in my development environment.
The production databases are in Mysql < 8.0 so, as per Bill Karwin's answer, I'm having trouble with my MySQL development environment version that is 8.0
It's not clear from your question why you want to eliminate the Extra information. It's just noting that the column's default is an expression.
To make the Extra field blank, you must make the column's default either a constant value or NULL.
mysql> create table foo ( id int unsigned primary key, start_date timestamp not null default current_timestamp);
mysql> show columns from foo;
+------------+------------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+-------------------+-------------------+
| id | int(10) unsigned | NO | PRI | NULL | |
| start_date | timestamp | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+------------+------------------+------+-----+-------------------+-------------------+
mysql> alter table foo modify start_date timestamp default null;
mysql> show columns from foo;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| start_date | timestamp | YES | | NULL | |
+------------+------------------+------+-----+---------+-------+
Note that the Extra information "DEFAULT_GENERATED" is only present in MySQL 8.0. I suspect it's related to the new feature to support expressions in the DEFAULT clause. Any other expression also results in this Extra information.
mysql > alter table foo modify start_date timestamp default (now() + interval 1 hour);
mysql> show columns from foo;
+------------+------------------+------+-----+---------------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------------+-------------------+
| id | int(10) unsigned | NO | PRI | NULL | |
| start_date | timestamp | YES | | (now() + interval 1 hour) | DEFAULT_GENERATED |
+------------+------------------+------+-----+---------------------------+-------------------+
Topicstarters comment
I have implemented a fingerprint validation method in PHP that diffs
the DESCRIBE tables values, I have database versions in production
that doesn't have that Extra value even though those columns have an
expression default value, so currently, I wish to alter that value so
I don't get errors from my implemented fingerprint validation method
in my development environment.
The more standard SQL method would be which also works in MySQL 8
Query
SELECT
information_schema.COLUMNS.COLUMN_NAME AS 'Field'
, information_schema.COLUMNS.COLUMN_TYPE AS 'Type'
, information_schema.COLUMNS.IS_NULLABLE AS 'Null'
, information_schema.COLUMNS.COLUMN_KEY AS 'Key'
, information_schema.COLUMNS.COLUMN_DEFAULT AS 'Default'
, information_schema.COLUMNS.EXTRA AS 'Extra'
FROM
information_schema.TABLES
INNER JOIN
information_schema.COLUMNS ON information_schema.TABLES.TABLE_NAME = information_schema.COLUMNS.TABLE_NAME
WHERE
information_schema.TABLES.TABLE_NAME = '<table>'
This query should match the output of DESCRIBE
Then you could use REPLACE() on information_schema.COLUMNS.EXTRA output to remove or edit the way you want. For example removing extra features like DEFAULT_GENERATED or VIRTUAL GENERATED (generated columns)
you need an alter table statement. Something like
ALTER TABLE `document` MODIFY COLUMN `start_date ` INT AUTO_INCREMENT;
You can set a default value like
DEFAULT 1 NOT NULL
I have 2 tables called applications and filters. The structure of the tables are as follows:
mysql> DESCRIBE applications;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| id | tinyint(3) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| filter_id | int(3) | NO | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> DESCRIBE filters;
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| label | varchar(255) | NO | | NULL | |
| link | varchar(255) | NO | | NULL | |
| anchor | varchar(100) | NO | | NULL | |
| group_id | tinyint(3) unsigned | NO | MUL | NULL | |
| comment | varchar(255) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
7 rows in set (0.02 sec)
What I want to do is select all the records in applications and make a corresponding record in filters (so that filters.name is the same as applications.name). When the record is inserted in filters I want to get the primary key (filters.id) of the newly inserted record - which is an auto increment field - and update applications.filter_id with it. I should clarify that applications.filter_id is a field I've created for this purpose and contains no data at the moment.
I am a PHP developer and have written a script which can do this, but want to know if it's possible with a pure MySQL solution. In pseudo-code the way my script works is as follows:
Select all the records in applications
Do a foreach loop on (1)
Insert a record in filters (filters.name == applications.name)
Store the inserted ID (filters.id) to a variable and then update applications.filter_id with the variable's data.
I'm unaware of how to do the looping (2) and storing the auto increment ID (4) in MySQL.
I have read about Get the new record primary key ID from mysql insert query? so am aware of LAST_INSERT_ID() but not sure how to reference this in some kind of "loop" which goes through each of the applications records.
Please can someone advise if this is possible?
I don't think this is possible to do this with only one request to mysql.
But, i think this is a good use case for mysql triggers.
I think you should write it like this :
CREATE TRIGGER after_insert_create_application_filter AFTER INSERT
ON applications FOR EACH ROW
BEGIN
INSERT INTO filters (name) VALUES (NEW.name);
UPDATE applications SET filter_id = LAST_INSERT_ID() WHERE id = NEW.id;
END
This trigger is not tested but you should understand the way to write it.
If you don't know mysql triggers, you can read this part of the documentation.
This isn't an answer to your question, more a comment on your database design.
First of all, if the name field needs to contain the same information, they should be the same type and size (varchar(255))
Overall though, I think the schema you're using for your tables is wrong. Your description says that each record in applications can only hold one filter_id. If that is the case, there's no point in using two separate tables.
If there is a chance that there will be a many-to-one relationship, link the records via the relevant primary key. If multiple records in application can relate to a single filter, store filters.id in the applications table. If there are multiple filters for a single application, store applications.id in the filters table.
If there is a many-to-many relationship, create another table to store it:
CREATE TABLE `application_filters_mappings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`application_id` int(10) unsigned NOT NULL,
`filters_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
I have a table that when I describe it is:
mysql> DESC my_table;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| contact_id | int(11) | NO | PRI | NULL | auto_increment |
| location | varchar(20) | YES | | NULL | |
| city | varchar(20) | YES | | NULL | |
| state | varchar(2) | YES | | NULL | |
+------------+-------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
My question is: why for the primary key contact_id the Default is displayed as NULL?
I created the table with NOT NULL for the column and the Primary Key can not be NULL anyway.
How can Null be NO and Default be NULL?
The fact that it can't be null makes the content of the 'default' column irrelevant. They are using 'null' in the 'default' column because otherwise they would need another magic value to indicate 'irrelevant', 'unused', end.
Don't worry about it.
NOT NULL in MySQL is used to indicate that the field can not be empty. In your case the Primary Key field contact_id is correctly shown as No in the attribute Null. Default clause in a data type specification indicates a default value for a column. Here your Primary Key Field contact_id does not have any default value. So it is shown as NULL.
Rest assured that even if the default column show a (NULL) value for the primary key field, it won't matter. Lets list every cases when Default has this (NULL) value :
if your SQL request provides a value to the primary field : Default is not called
if your SQL request doesnt provide a value but is an autoincrement field : Defaut is not called
if your SQL request doesnt provide a value and the field is not an autoincrement and can be null : Default is called and NULL is inserted
if your SQL request doesnt provide a value and the field is not an autoincrement and can NOT be null : Default is called but you get an error telling you that this field "cannot be null"
Hope this helps.
In your case, NULL in the default column indicates that the user didn't specify any value as the default value.
I have a string in database (mysql) which is like:
{"StateId":73,"CallTime":"\/Date(1336365498912+0500)\/","CallId":"1336365489.14157","Target":"agi://127.0.0.1"}},"Profile":{"$type":"DataWriter.DbProfile, DataWriterObjects","Name":"DataService","Provider":"mssql","ConnectionString":"Data Source=localhost\\mydb; Database=mydb; User Id=sa; Password=admin;"}}
The string is a JSON object which contains multiple fields. The problem is that I have multiple duplicate rows which I want to remove from the database. A row is considered a duplicate if the CallId and StateId is same but the CallTime is different. So first I want to get list of the duplicates (GROUP BY) of those rows which have CallId same and ignore the difference in CallTime. The below record has different CallTime from the first one but same CallId, hence it is considered a duplicate (basically need not to consider CallTime for duplicate)
{"StateId":73,"CallTime":"\/Date(1336365498913+0500)\/","CallId":"1336365489.14157","Target":"agi://127.0.0.1"}},"Profile":{"$type":"DataWriter.DbProfile, DataWriterObjects","Name":"DataService","Provider":"mssql","ConnectionString":"Data Source=localhost\\mydb; Database=mydb; User Id=sa; Password=admin;"}}
So how do I do a GROUP BY? Basically everything in the GROUP BY should be matched ignoring the CallTime value.
The table structure is
mysql> describe Statements;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| SequenceId | bigint(10) | NO | PRI | NULL | auto_increment |
| Profile | varchar(32) | YES | MUL | NULL | |
| CacheItem | text | NO | | NULL | |
+------------+-------------+------+-----+---------+----------------+
After that I want to delete the duplicates. Anyone help me out?
I think your database is not atomic enough, you may have to split out your JSON string into separate fields
I am changing a column from text to varchar column.
+------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| ID | bigint(19) | NO | PRI | NULL | |
| STATUS | varchar(120) | YES | | NULL | |
| PRIORITY | varchar(120) | YES | | NULL | |
| DESCRIPTION | text | YES | | NULL | |
when i execute the below query,
alter table StatInfo modify column DESCRIPTION varchar(255) NULL;
It says
ERROR 1406 (22001): Data too long for column 'DESCRIPTION' at row 7
It doesn't truncates the value in the column and alters the table why?. where as in older version it works.
May be you need to check the sql mode, if it strict then it will show this error
When you change a data type using CHANGE or MODIFY, MySQL tries to
convert existing column values to the new type as well as possible.
Warning This conversion may result in alteration of data. For example,
if you shorten a string column, values may be truncated. To prevent
the operation from succeeding if conversions to the new data type
would result in loss of data, enable strict SQL mode before using
ALTER TABLE (see Section 5.1.6, “Server SQL Modes”).
http://dev.mysql.com/doc/refman/5.1/en/alter-table.html
I suggest you to
1) Copy that table on a temporary table (through an insert-select)
2) Alter the original table
3) Restore the values in the original table using the same procedure described in 1)