SQL Server, can't insert null into primary key field? - sql

I'm about ready to rip my hair out on this one. I'm fairly new to MS SQL, and haven't seen a similar post anywhere.
When I try to do a statement like this:
INSERT INTO qcRawMatTestCharacteristic
VALUES(NULL, 1,1,1,1,1,1,1,'','','', GETDATE(), 1)
I get the following:
Cannot insert the value NULL into
column 'iRawMatTestCharacteristicId',
table
'Intranet.dbo.qcRawMatTestCharacteristic';
column does not allow nulls. INSERT
fails.
I understand the error, but the null value is for my my primary field with an int data type.
Any ideas!?

Primary keys in any relational database are not allowed to be NULL - it's one of the main, fundamental characteristics of a primary key.
See: SQL by Design: how to Choose the primary key
Never Null
No primary key value can be null, nor can you do anything to
render the primary key null. This is
an inviolate rule of the relational
model as supported by ANSI, of
relational database management system
(RDBMS) design, and of SQL Server.
UPDATE: ok, so you want an "auto-increment" primary key in SQL Server.
You need to define it as an INT IDENTITY in your CREATE TABLE statement:
CREATE TABLE dbo.YourTable(ID INT IDENTITY, col1 INT, ..., colN INT)
and then when you do an INSERT, you need to explicitly specify the columns to insert, but just don't specify the "ID" column in that list - then SQL Server will handle finding the proper value automagically:
INSERT INTO dbo.YourTable(col1, col2, ..., colN) -- anything **except** `ID`
VALUES(va1l, val2, ..., valN)
If you want to do this after having created the table already, you can do so in the SQL Server Management Studio's table designer:

Primary Key fields cannot contain null values in MS SQL. If you want to populate a SQL table and dont know what to enter for a integer based primary key field then set the pk to an Identity field. Also when specifying Insert statements its wise to use the column mapping portion of the insert statment for example:
Insert into (field1, field2, field3)
values
(value1, value2, value3)
The reason for this is it insures that the column order is what you developed for as a SQL administrator can modify column order. It also allows you to insert a row with an identity Primary key with out specifying the value of the Primary Key Example
CREATE TABLE [dbo].[foo](
[fooid] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
CONSTRAINT [PK_foo] PRIMARY KEY
(
[fooid] ASC
)
now my insert statement is simple
Insert into foo (name)
values
("John")
the result in the table would be
1, "John"

You probably don't have (you forgot to add) autoincrement set on your integer primary key.

Primary keys shouldnt accept null value.Why you are inserting null values to a primary key field ?Primary key field should have a non-nullable,unique value which will make each of your record in the table unique

you can use 0 instead of null for only 1 unique row, null is not possible for PK. Or you can omit PK and use and auto increament PK field

Assuming you have an autoincrement field for your primary Key you'll need to include the field list on your insert and not put a value for that field e.g.
INSERT INTO qcRawMatTestCharacteristic
(Answer1,Answer2,...SomeDateField)
VALUES(1,1,1,1,1,1,1,'','','', GETDATE(), 1)

I'm assuming your real issue is that you're not sure how to write an insert statement so that the PK is auto populated correct? You need to name the fields you're setting values for, it looks like you're trying to set all of them but just exclude the PK field like so:
INSERT INTO someTable
(fieldName1, fieldName2)
VALUES(1,1)
Where sometable is a table with three fields. PK, fieldName1, and fieldName2. You also need to make sure that the identity property on the PK field is set to true.

if you have an identity column, you don't need to specify it in the insert statement.
INSERT INTO qcRawMatTestCharacteristic
VALUES(1,1,1,1,1,1,1,'','','', GETDATE(), 1)
However, if you have a primary key that isn't an identity column, then you do need to specify it, because otherwise it'll try to insert a null and primary keys by default are non-nullable.

Related

No auto increment in my foreign key

I'm working in my school project and I want to make the id subject of any student incremented automatically as foreign key. I am showing you the example below as prototype, there are two tables, when I'm trying to insert data into the second table, I get an error (necessary to insert another field id of the table)
CREATE DATABASE database1;
USE database1;
CREATE TABLE table1
(
IdTable1 INT NOT NULL IDENTITY,
NOM VARCHAR(30),
PRIMARY KEY(IDMEDO)
);
--auto increment is working here
INSERT INTO table1
VALUES ('data1Table1'), ('data2Table1'), ('data3Table1');
--auto increment is working here just with the primary key
CREATE TABLE table2
(
IdTable2 INT not null IDENTITY,
IdTable1 INT,
dataTable2 varchar(30),
primary key(IdTable2),
constraint fk_tbl1 foreign key(IdTable1) references Table1
);
--necessary to add id field
INSERT INTO table2
VALUES ('data1Table2'), ('data2Table2'), ('data3Table2');
You should always (as a "best practice") define the columns you want to insert data into - that way, you can specify those that you have to provide values for, and let SQL Server handle the others. And for the foreign key, you have to explicitly provide a value - there's no "auto-magic" (or "auto-incrementing") way of associating a child row with its parent table - you have to provide the value in your INSERT statement.
So change your code to:
-- explicitly *specify* the NOM column here!
INSERT INTO table1 (NOM)
VALUES ('data1Table1'), ('data2Table1'), ('data3Table1');
-- again: explicitly *specify* the columns you want to insert into!
INSERT INTO table2 (IdTable1, dataTable2)
VALUES (1, 'data1Table2'), (2, 'data2Table2'), (3, 'data3Table2');
You need to insert the value of the foreign key wrt to table 1 now if you enter a value that's not in table 1 column which is acting as a foreign key then also it will not accept
Simply
Primary key and foreign key should match
Foreign key can't be null if table 1 doesn't contain a primary key with value null

How to ignore duplicate Primary Key in SQL?

I have an excel sheet with several values which I imported into SQL (book1$) and I want to transfer the values into ProcessList. Several rows have the same primary keys which is the ProcessID because the rows contain original and modified values, both of which I want to keep. How do I make SQL ignore the duplicate primary keys?
I tried the IGNORE_DUP_KEY = ON but for rows with duplicated primary key, only 1 the latest row shows up.
CREATE TABLE dbo.ProcessList
(
Edited varchar(1),
ProcessId int NOT NULL PRIMARY KEY WITH (IGNORE_DUP_KEY = ON),
Name varchar(30) NOT NULL,
Amount smallmoney NOT NULL,
CreationDate datetime NOT NULL,
ModificationDate datetime
)
INSERT INTO ProcessList SELECT Edited, ProcessId, Name, Amount, CreationDate, ModificationDate FROM Book1$
SELECT * FROM ProcessList
Also, if I have a row and I update the values of that row, is there any way to keep the original values of the row and insert a clone of that row below, with the updated values and creation/modification date updated automatically?
How do I make SQL ignore the duplicate primary keys?
Under no circumstances can a transaction be committed that results in a table containing two distinct rows with the same primary key. That is fundamental to the nature of a primary key. SQL Server's IGNORE_DUP_KEY option does not change that -- it merely affects how SQL Server handles the problem. (With the option turned on it silently refuses to insert rows having the same primary key as any existing row; otherwise, such an insertion attempt causes an error.)
You can address the situation either by dropping the primary key constraint or by adding one or more columns to the primary key to yield a composite key whose collective value is not duplicated. I don't see any good candidate columns for an expanded PK among those you described, though. If you drop the PK then it might make sense to add a synthetic, autogenerated PK column.
Also, if I have a row and I update the values of that row, is there any way to keep the original values of the row and insert a clone of that row below, with the updated values and creation/modification date updated automatically?
If you want to ensure that this happens automatically, however a row happens to be updated, then look into triggers. If you want a way to automate it, but you're willing to make the user ask for the behavior, then consider a stored procedure.
try this
INSERT IGNORE INTO ProcessList SELECT Edited, ProcessId, Name, Amount, CreationDate, ModificationDate FROM Book1$
SELECT * FROM ProcessList
You drop the constraint. Something like this:
alter table dbo.ProcessList drop constraint PK_ProcessId;
You need to know the constraint name.
In other words, you can't ignore a primary key. It is defined as unique and not-null. If you want the table to have duplicates, then that is not the primary key.

prevent autoincrementing integer primary key?

I have a sqlite table (sqlite version 3.7.3) where nulls inserted into the primary key column are being undesirably auto-incremented:
sqlite> CREATE TABLE foo(bar INTEGER NOT NULL PRIMARY KEY);
sqlite> INSERT INTO foo(bar) VALUES(NULL);
sqlite> SELECT * FROM foo;
1
In the sqlite docs, it shows that adding the AUTOINCREMENT keyword to the column should create this behavior, but there doesn't appear to be a keyword to prevent the auto incrementing...
I also found that I can build sqlite with the SQLITE_OMIT_AUTOINCREMENT compile option, but I don't want to disable the behavior globally, just for this particular column.
Interestingly, if I don't include the PRIMARY KEY constraint, I get the desired behavior:
sqlite> CREATE TABLE FOO(bar integer NOT NULL);
sqlite> INSERT INTO FOO(bar) VALUES(NULL);
SQL error: foo.bar may not be NULL
How can I define the table so that NULL values are rejected and keep the primary key constraint?
Autoincrement behavior applies only to columns declared as INTEGER PRIMARY KEY. So the easiest ways to disable it are:
Declare the column as UNIQUE instead of PRIMARY KEY.
Declare the column type as INT instead of INTEGER.
Note that either one will give you a column with integer affinity instead of being constrained to contain only integers.
One way to disable autoincrement (outside of recreating the table) when you need to insert data is to use the import tool in sqlite3:
If you have a table like this:
CREATE TABLE [table1] ( [ID] integer PRIMARY KEY AUTOINCREMENT NOT NULL, [col1] TEXT);
If you run the import command on it with your data file:
ID col1
10 abc
20 def
import myfile.txt table1
It will import the rows, and it will disregard the autoincrement feature.

Will multiply insert requests to the same table with direct query and store-procedure cause collision?

Multiply users can call store procedure(SP), that will make some changes to mytable in SQL Server. This SP should insert some rows to mytable that has reference to itself through parentid column.
TABLE mytable(
id int identity(1,1) primary key,
name varchar(20) not null,
parentId int not null foreign key references mytable(id)
)
in order to insert row to such table, accordingly to other posts, I have 2 ways:
Allow null to parentid column by ALTER TABLE mytable alter column parentid int null;, insert the row, update parentid and than disable null to parentid
Allow IDENTITY by set identity_insert maytable on, insert dummy row with id=-1 and parentid=-1, insert the correct row with reference to -1, update the parentid to SCOPE_IDENTITY() and in the end set IDENTITY to off
The case:
Assume I take the 2nd way. SP managed to set identity_insert mytable on BUT didn't yet finished the execution of the rest SP. At this time, there are other INSERT requests(NOT through SP) to the mytable table like INSERT INTO mytable(name,parentid) VALUES('theateist', -1). No id is specified because they assumed that IDENTITY is off and therefore id is auto-incremental.
The Question:
Will this cause errors while inserting because IDENTITY, in this period of time, is ON and not auto-incremental any more and therefore it will require id specification? If yes, it will be better to use the 1st way, isn't it?
Thank you
identity_insert is a per-connection setting - you won't affect other connections/statements running against this table.
I definitely wouldn't suggest going the first way, if it could be avoided, since it could impact other users of the table - e.g. some other connection could do a broken insert (parentid=null) while the column definition allows it, and then your stored proc will break. Also, setting a column not null forces a full table scan to occur, so this won't work well as the table grows.
If you did stick with method 2, you've still got an issue with what happens if two connections run this stored proc simultaneously - they'll both want to insert the -1 row, at different times, and delete it also. You'll have conflicts.
I'm guessing the problem you're having is inserting the "roots" of the tree(s), since they have no parent, and so you're attempting to have them self referencing. I'd instead probably make the roots have a null parentid permanently. If there's some other key column(s), these could be used in a filtered index or indexed view to ensure that only one root exists for each key.
Imagine that we're building some form of family trees, and ignoring most of the realities of such beasts (such as most families requiring children to have two parents):
CREATE TABLE People (
PersonID int IDENTITY(1,1) not null,
Surname varchar(30) not null,
Forename varchar(30) not null,
ParentID int null,
constraint PK_People PRIMARY KEY (PersonID),
constraint FK_People_Parents FOREIGN KEY (ParentID) references People (PersonID)
)
CREATE UNIQUE INDEX IX_SoleFamilyRoot ON People (Surname) WHERE (ParentID is null)
This ensures that, within each family (as identified by the surname), exactly one person has a null ParentID. Hopefully, you can modify this example to fit your model.
On SQL Server 2005 and earlier, you have to use an indexed view instead.

How to create a unique index on a NULL column?

I am using SQL Server 2005. I want to constrain the values in a column to be unique, while allowing NULLS.
My current solution involves a unique index on a view like so:
CREATE VIEW vw_unq WITH SCHEMABINDING AS
SELECT Column1
FROM MyTable
WHERE Column1 IS NOT NULL
CREATE UNIQUE CLUSTERED INDEX unq_idx ON vw_unq (Column1)
Any better ideas?
Using SQL Server 2008, you can create a filtered index.
CREATE UNIQUE INDEX AK_MyTable_Column1 ON MyTable (Column1) WHERE Column1 IS NOT NULL
Another option is a trigger to check uniqueness, but this could affect performance.
The calculated column trick is widely known as a "nullbuster"; my notes credit Steve Kass:
CREATE TABLE dupNulls (
pk int identity(1,1) primary key,
X int NULL,
nullbuster as (case when X is null then pk else 0 end),
CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster)
)
Pretty sure you can't do that, as it violates the purpose of uniques.
However, this person seems to have a decent work around:
http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html
It is possible to use filter predicates to specify which rows to include in the index.
From the documentation:
WHERE <filter_predicate> Creates a filtered index by specifying which
rows to include in the index. The filtered index must be a
nonclustered index on a table. Creates filtered statistics for the
data rows in the filtered index.
Example:
CREATE TABLE Table1 (
NullableCol int NULL
)
CREATE UNIQUE INDEX IX_Table1 ON Table1 (NullableCol) WHERE NullableCol IS NOT NULL;
Strictly speaking, a unique nullable column (or set of columns) can be NULL (or a record of NULLs) only once, since having the same value (and this includes NULL) more than once obviously violates the unique constraint.
However, that doesn't mean the concept of "unique nullable columns" is valid; to actually implement it in any relational database we just have to bear in mind that this kind of databases are meant to be normalized to properly work, and normalization usually involves the addition of several (non-entity) extra tables to establish relationships between the entities.
Let's work a basic example considering only one "unique nullable column", it's easy to expand it to more such columns.
Suppose we the information represented by a table like this:
create table the_entity_incorrect
(
id integer,
uniqnull integer null, /* we want this to be "unique and nullable" */
primary key (id)
);
We can do it by putting uniqnull apart and adding a second table to establish a relationship between uniqnull values and the_entity (rather than having uniqnull "inside" the_entity):
create table the_entity
(
id integer,
primary key(id)
);
create table the_relation
(
the_entity_id integer not null,
uniqnull integer not null,
unique(the_entity_id),
unique(uniqnull),
/* primary key can be both or either of the_entity_id or uniqnull */
primary key (the_entity_id, uniqnull),
foreign key (the_entity_id) references the_entity(id)
);
To associate a value of uniqnull to a row in the_entity we need to also add a row in the_relation.
For rows in the_entity were no uniqnull values are associated (i.e. for the ones we would put NULL in the_entity_incorrect) we simply do not add a row in the_relation.
Note that values for uniqnull will be unique for all the_relation, and also notice that for each value in the_entity there can be at most one value in the_relation, since the primary and foreign keys on it enforce this.
Then, if a value of 5 for uniqnull is to be associated with an the_entity id of 3, we need to:
start transaction;
insert into the_entity (id) values (3);
insert into the_relation (the_entity_id, uniqnull) values (3, 5);
commit;
And, if an id value of 10 for the_entity has no uniqnull counterpart, we only do:
start transaction;
insert into the_entity (id) values (10);
commit;
To denormalize this information and obtain the data a table like the_entity_incorrect would hold, we need to:
select
id, uniqnull
from
the_entity left outer join the_relation
on
the_entity.id = the_relation.the_entity_id
;
The "left outer join" operator ensures all rows from the_entity will appear in the result, putting NULL in the uniqnull column when no matching columns are present in the_relation.
Remember, any effort spent for some days (or weeks or months) in designing a well normalized database (and the corresponding denormalizing views and procedures) will save you years (or decades) of pain and wasted resources.