MS SQL explicitly using "default defaults" on NOT NULL fields - why? - sql

I stumbled upon this definition:
CREATE TABLE dbo.whatever (
[flBlahBlah] BIT DEFAULT ((0)) NOT NULL,
[txCity] NVARCHAR (50) DEFAULT ('') NOT NULL,
[cdFrom] VARCHAR (10) DEFAULT ('') NOT NULL
);
I can't think of a reason to add those default values. Not null string is defaulted to '' and bit is defaulted to 0. Is there a reason for defining these default values? Am I missing something? Is this in some best practice handbook I'm not aware of?
I'd just use:
CREATE TABLE dbo.whatever (
[flBlahBlah] BIT NOT NULL,
[txCity] NVARCHAR (50) NOT NULL,
[cdFrom] VARCHAR (10) NOT NULL
);
The database is in MS SQL Server 2012, now migrating to Azure Database.

For example you create table from a first batch of your question. Then insert value like this
INSERT INTO dbo.whatever (flBlahBlah) VALUES (1)
You will get 1 row dbo.whatever
flBlahBlah txCity cdFrom
1
So if you "forget" to insert in one of the column with default values determined - SQL Server will take care of them.
It is very useful when you got table, in which you need to insert new field. With default value determined you don't need to change SP/query's/other stuff that works with this table.

Related

Cannot insert the value NULL into column X, column X does not allow nulls. INSERT fails.

I'm new to SQL Server and I am getting this error "Cannot insert the value NULL into column 'Occupied', table 'DBProjectHamlet.dbo.tblGrave'; column does not allow nulls. INSERT fails. The statement has been terminated."
This is my code for the insert followed by the code to create the table
INSERT INTO tblGrave (GraveName)
SELECT Grave
FROM tblPlotsandOccupants
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'tblGrave' AND TABLE_SCHEMA = 'dbo')
DROP TABLE dbo.tblGrave;
GO
CREATE TABLE tblGrave
(
GraveID INT IDENTITY (1,1),
GraveName VARCHAR(MAX) NULL,
GraveTypeID INT NOT NULL,
PlotID INT NOT NULL,
Occupied BIT NOT NULL
)
I'm not trying to insert anything into column Occupied, I don't know why this is happening or how to fix it. I just want to insert values into tblGrave (GraveName). Any help would be great.
Exactly! You aren't doing anything with Occupied and that is the problem. The column is specified to be NOT NULL but has no default value. You are not inserting a value, so it gets the default. The default default is NULL, and that is not allowed.
One simple solution is:
INSERT INTO tblGrave (GraveName, Occupied)
SELECT Grave, 0
FROM tblPlotsandOccupants;
This fixes your immediate problem, but will then you will get an error on PlotId.
A more robust solution would add a default value for the NOT NULL columns and declare the rest to be nullable (the default). Something like this:
CREATE TABLE tblGrave (
GraveID INT IDENTITY (1,1) PRIMARY KEY,
GraveName VARCHAR(MAX),
GraveTypeID,
PlotID INT,
Occupied BIT NOT NULL DEFAULT 0
);
When you created your table, you defined that column as "NOT NULL" rather than allowing it to be null.
You need to either allow "Occupied" to be null, set a default value, or define the value that you want upon inserting.
You can even set the value to be ' ' which is blank but isn't null.
EDIT
Note #Gordon's answer for sql examples.

cannot change null to not null

The column name on table [dbo].[payment_info] must be changed from NULL to NOT NULL. If the table contains data, the ALTER script may not work.
To avoid this issue, you must add values to this column for all rows or mark it as allowing NULL values, or enable the generation of smart-defaults as a deployment option.
CREATE TABLE [dbo].[payment_info]
(
[name] VARCHAR (50) NOT NULL,
[card_no] VARCHAR (50) NULL,
[card_type] VARCHAR (50) NOT NULL,
[tel_no] VARCHAR (50) NULL,
[mob_no] VARCHAR (50) NULL,
[address] VARCHAR (MAX) NULL
);
I cannot change NULLto NOT NULL; when I update it's showing the above warning.
I am using visual studio 2013 asp.net and c#.
If table already exists and is fulfilled with data, you have to update all NULLs in column you want to change on some value which is not NULL. Then ALTER command should work wthout warnings and/or errors.
I am not really sure if I understood your problem correctly, but the warning says it all - you can't switch column to not nullable, if there are nulls already in the column.
You have to update and set some values to empty entries or set DEFAULT value
EDIT:
You should try first:
select *
from [dbo].[payment_info]
where name is null
and check if there are any problems
Right-click on your table in server explorer and click "new query". Type:
ALTER TABLE
table
ALTER COLUMN
column
int NOT NULL;
This error is produced by SSDT. This will happen if you have an existing table and you would like to add a new non-nullable column to it. In order to do so, you must have a default for this new column (the default can be some temporary value).
CREATE TABLE [dbo].[payment_info]
(
[WhateverColumn] VARCHAR (50) NOT NULL DEFAULT 'Foo',
-- and so on
);
If you want to change the default to a more meaningful value, you can write the script to update the table and set the column's value to a more meaningful value in a post deployment. In post deployment you can also now drop the default since it was temporary:
ALTER TABLE WhateverTable
ALTER COLUMN WhateverColumn DROP DEFAULT;
Now your deployment will succeed.
Note: If your column is a foreign-key column, the default has to exist in the parent table even if the value is temporary.

SQL Server - Default value

I don't know if this is possible, but i would like to know if when we create a table on which a field has a default value, we can make this Default value get the value of another column upon row insertion.
Create Table Countries (
ID Int Not Null Identity(1,1),
CountryCode Char (2) Not Null,
Country Varchar (50) Not Null,
CountryRegion Varchar (50) Null Default ('Country'),
Nationality Varchar (75) Not Null Default ('Not Known'),
InsertDate Datetime2 Not Null Default Getdate(),
Constraint PK_CountryCode Primary Key (CountryCode));
On CountryRegion field, I could place an ('Unknown') default value, but like I said, is it possible this field gets by default the value inserted on Country field if nothing is placed on it?
Using a trigger would do - UPDATE a column right after insertion
CREATE TRIGGER CountriesTrigger ON Countries AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE Countries
SET
Countries.CountryRegion = inserted.Country
FROM Countries, inserted
WHERE Countries.ID = inserted.ID
AND inserted.CountryRegion is null
END
I think there is no easy of doing this at TABLE level. There are some workarounds to do this :
1. If you are using stored procs then you can write your logic over there.
2. Trigger is also an option but overhead in terms of execution.
Thanks.

Selecting from a table and inserting into another table's column of a different type using query in ms access

I have some txt files that contain tables with a mix of different records on them which have diferent types of values and definitons for columns. I was thinking of importing it into a table and running a query to separate the different record types since a identifier to this is listed in the first column. Is there a way to change the value type of a column in a query? since it will be a pain to treat all of them as text. If you have any other suggestions on how to solve this please let me know as well.
Here is an example of tables for 2 record types provided by the website where I got the data from
create table dbo.PUBACC_A2
(
Record_Type char(2) null,
unique_system_identifier numeric(9,0) not null,
ULS_File_Number char(14) null,
EBF_Number varchar(30) null,
spectrum_manager_leasing char(1) null,
defacto_transfer_leasing char(1) null,
new_spectrum_leasing char(1) null,
spectrum_subleasing char(1) null,
xfer_control_lessee char(1) null,
revision_spectrum_lease char(1) null,
assignment_spectrum_lease char(1) null,
pfr_status char(1) null
)
go
create table dbo.PUBACC_AC
(
record_type char(2) null,
unique_system_identifier numeric(9,0) not null,
uls_file_number char(14) null,
ebf_number varchar(30) null,
call_sign char(10) null,
aircraft_count int null,
type_of_carrier char(1) null,
portable_indicator char(1) null,
fleet_indicator char(1) null,
n_number char(10) null
)
Yes, you can do what you want. In ms access you can use any VBA functions and with some
IIF(FirstColumn="value1", CDate(SecondColumn), NULL) as DateValue,
IIF(FirstColumn="value2", CDec(SecondColumn), NULL) as DecimalValue,
IIF(FirstColumn="value3", CStr(SecondColumn), NULL) as StringValue
You can use all/any of the above in your SELECT.
EDIT:
From your comments it seems that you want to split them into different tables - importing as text should not be a problem in that case.
a)
After you import and get it in the initial table, create the proper table manually setting you can INSERT into the proper table.
b)
You could even do a make table query, but it might be faster to create it manually. If you do a make table query you have to be sure that you have casted the data into proper type in your select.
EDIT2:
As you updated the question showing the structure it becomes obvious that my suggestion above will not help directly.
If this is one time process you can follow HLGEM's solution. Here are some more details.
1) Import into a table with two columns - RecordType char(2), Rest memo
2) Now you can split the data (make two queries that select based on RecordType) and re-export the data (to be able to use access' import wizard)
3) Now you have two text files with proper structure which can be easily imported
I did this in my last job. You start with a staging table that has one column or two coulmns if your identifier is always the same length.
Then using the record identifier, you move the data to another set of staging tables, one for each type of record you have. This will be in columns for the data and can have the correct data types. Then you do any data cleaning you need to do. Then you insert into the real production table.
If you have a column defined as text, because it has both alphas and numbers, you'll only be able to query it as if it were text. Once you've separated out the different "types" of data into their own tables, you should be able to change the schema definition. Please comment here if I'm misunderstanding what you're trying to do.

mysql warnings

I have the following table:
CREATE TABLE `events` (
`evt_id` int(11) NOT NULL AUTO_INCREMENT,
`evt_name` varchar(50) NOT NULL,
`evt_description` varchar(100) DEFAULT NULL,
`evt_startdate` date NOT NULL,
`evt_enddate` date DEFAULT NULL,
`evt_starttime` time DEFAULT NULL,
`evt_endtime` time DEFAULT NULL,
`evt_amtpersons` int(11) DEFAULT NULL,
`sts_id` int(11) NOT NULL,
`adr_id` int(11) DEFAULT NULL,
`evt_amtPersonsSubs` int(11) DEFAULT NULL,
`evt_photo` varchar(50) DEFAULT NULL,
`sys-mut-dt` timestamp NULL DEFAULT NULL,
`sys-mut-user` varchar(20) DEFAULT NULL,
`sys-mut-id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`evt_id`),
KEY `sts_id` (`sts_id`),
KEY `adr_id` (`adr_id`),
CONSTRAINT `sts_id` FOREIGN KEY (`sts_id`) REFERENCES `statusses` (`sts_id`) O
N DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
Now I have got two problems:
Here is my query:
INSERT INTO `events`(`evt_name` , `evt_description` , `evt_startdate` , `evt_enddate` , `evt_starttime` , `evt_endtime` , `evt_amtpersons` , `sts_id` , `adr_id` , `evt_amtPersonsSubs` , `evt_photo` , `sys-mut-user` , `sys-mut-id`) VALUES ('asf' , 'asf' , '2009-04-02' , '2009-04-22' , '00:00:00' , '00:00:00' , '3' , '1' , '' , '' , '' , 'test' , '1')
When I execute this query through my php programs I get no error. But when I execute the query in a shell directly on the mysql database I get two warnings. How can I get PHP to alert me when there are warnings because if there are warnings mysql doesn't do the insert.
About the warnings:
| Warning | 1366 | Incorrect integer value: '' for column 'adr_id' at row 1
| Warning | 1366 | Incorrect integer value: '' for column 'evt_amtPersonsSubs' a t row 1
How can I get rid of these warnings. Tried to make some changes but it didn't work out so far.
You are inserting an empty string. You should remove the '' and put a number in that field
As you said, the column does not have to have a value specified when you insert. The fact is indicated by the "DEFAULT NULL" for that column at table creation. This fact, however, means that if you do not specify the column name in your list of columns while doing INSERT (and therefore you will not specify the corresponding value either), then the tuple can be inserted anyway, and for that column value you will get a NULL automagically by default.
However, in your query you specify that you are going to insert that column value, and the column value you say is '' (an empty string). This is of course not valid, because that column accepts integers (or NULL, because you havent' declared the column NOT NULL), and an empty string is an empty string, not an integer.
The SQL server is generous and accepts the empty string anyway (probably it casts it to zero) but reports you a warning. If you set a strict mode for the server (something I strongly suggest you to do), you will get an error and the insert will fail.
Please note that if you follow my suggestion of setting strict mode, this is server wide, involving all your databases and all your tables (at least with the mysql released one year ago). If you have awfully written software that need a forgiving server, then you cannot use it.
The error message tells you that that the empty string ('') is not a valid value for an integer field - in this case the fields adr_id and evt_amtPersonsSubs. Did you mean to put NULL instead?
In PHP, you can retrieve the error or warning message, for the most recent query only, using the mysql_error() function.
'' is not an integer.... how about using NULL in the query if you actually want a null value?
The warnings tell you that you're trying to insert a string value into an integer column.
In all the places where you have an int column you must not put the value between ' but just put the value as is
[...]'00:00:00' , '00:00:00' , 3 , 1 , [...]
If you don't want to provide a value for a certain column you should define the column with NULL. Then you can even leave your '' for the insert.
BUT
In general it's bad practice to do inserts like that. What if you one day need to add a column to your table? Then you have to go and rewrite your code as well.
Therefore you should do inserts like that:
INSERT INTO tbl_name (col1, col2) VALUES(value1, value2);
This way your code will still work, even if you decide to add columns. Plus the code is easier to read!!
Implicit defaults are defined as follows:
For numeric types, the default is 0, with the exception that for integer or floating-point types declared with the AUTO_INCREMENT
attribute, the default is the next value in the sequence.
Reference:
MySQL 5.7 Reference Manual / Data Types / Data Type Default Values