How to create Unique key for a varchar column for entity framework database? - sql

I had watch youtube video tutorial teaching how to create unique key
http://www.youtube.com/watch?v=oqrsfatxTYE&list=PL08903FB7ACA1C2FB&index=9
In the video, he has created a unique key for Email(nvarchar) column, I could create it when I create database manually, but when I try create unique key for a database created with entity framework code first, using the next query
ALTER TABLE Peoples
ADD CONSTRAINT UQ_MyTable_Email UNIQUE (email)
It will generate a error:
Msg 1919, Level 16, State 1, Line 2
Column 'email' in table 'Peoples' is of a type that is invalid for use as a key column in an index.
What is problem? what can I do for create unique key for nvarchar(max) column?

say If you create this table
CREATE TABLE ConstTable
(ID INT,
Email VARCHAR(1000)
CONSTRAINT uc_Email UNIQUE (Email)
)
GO
you will get a warning :
Warning! The maximum key length is 900 bytes. The index 'uc_Email' has
maximum length of 1000 bytes. For some combination of large values,
the insert/update operation will fail
Your column on which you want to define a unique constraint should be less then or equal to 900 bytes, so you can have a VARCHAR(900) or NVARCHAR(450) column if you want to be able to create a unique constraint on that column
Same table above with VARCHAR(450) gets created without any warning
CREATE TABLE ConstTable
(ID INT,
Email VARCHAR(900)
CONSTRAINT uc_Email UNIQUE (Email)
)
GO
Result
Command(s) completed successfully.
Test For your Table
say this is your table
CREATE TABLE ConstTable
(ID INT,
Email VARCHAR(MAX)
)
GO
Now try to create any index on the VARCHAR(MAX) data type and you will get the same error.
CREATE INDEX ix_SomeIdex
ON ConstTable (Email)
Error Message
Msg 1919, Level 16, State 1, Line 1 Column 'Email' in table
'ConstTable' is of a type that is invalid for use as a key column in
an index.

Related

Why is the column not altering when I try to convert it to UUID?

I have a primary key column in my SQL table in PostgreSQL named "id". It is a "bigseries" column. I want to convert the column to a "UUID" column. It entered the below command in the terminal:
alter table people alter column id uuid;
and
alter table people alter column id uuid using (uuid_generate_v4());
but neither of them worked.
In both tries I got the error message
ERROR: syntax error at or near "uuid"
LINE 1: alter table people alter column id uuid using (uuid_generate...
What is the correct syntax?
First of all uuid_generate_v4() is a function which is provided by an extension called uuid-ossp. You should have install that extension by using;
CREATE EXTENSION uuid-ossp;
Postgresql 13 introduced a new function which does basically the same without installing extension. The function is called gen_random_uuid()
Suppose that we have a table like the one below;
CREATE TABLE people (
id bigserial primary key,
data text
);
The bigserial is not a real type. It's a macro which basically creates bigint column with default value and a sequence. The default value is next value of that sequence.
For your use case, to change data type, you first should drop the old default value. Then, alter the type and finally add new default value expression. Here is the sample:
ALTER TABLE people
ALTER id DROP DEFAULT,
ALTER id TYPE uuid using (gen_random_uuid() /* or uuid_generate_v4() */ ),
ALTER id SET DEFAULT gen_random_uuid() /* or uuid_generate_v4() */ ;
CREATE TABLE IF NOT EXISTS people (
id uuid NOT NULL CONSTRAINT people_pkey PRIMARY KEY,
address varchar,
city varchar(255),
country varchar(255),
email varchar(255),
phone varchar(255)
);
This is the correct syntax to create table in postgres SQL, it's better to do these constraints at beginning to avoid any error.
For using alter command you would do the following:
ALTER TABLE customer ADD COLUMN cid uuid PRIMARY KEY;
Most of errors that you could find while writing command either lower case or undefined correct the table name or column.

Use user-defined function in CREATE TABLE statement

I'm trying to create the following table
CREATE TABLE Ingredient.Ingredient
(
GUID UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL,
Name NVARCHAR(MAX) NOT NULL UNIQUE
)
but I've come to realize that the max size of a NVARCHAR UNIQUE column is 450 (at least in the current version of SQL Server). In order to not use magic literals I've created a user-defined function that returns the current max size of a NVARCHAR UNIQUE column.
CREATE FUNCTION [Max NVARCHAR Index Size]()
RETURNS INTEGER
BEGIN
RETURN(450)
END
This function runs correctly when called as
SELECT dbo.[Max NVARCHAR Index Size]()
I was hoping to use this function in a CREATE TABLE statement, but it errors as shown below.
CREATE TABLE Ingredient.Ingredient
(
GUID UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL,
Name NVARCHAR(dbo.[Max NVARCHAR Index Size]()) NOT NULL UNIQUE
)
Error:
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near '('
To try and circumvent this I made a variable with the value of the function, and then using the variable, but that didn't work either.
DECLARE
#NVARCHARIndexSize INTEGER = dbo.[MAX NVARCHAR Index Size]()
CREATE TABLE Ingredient.Ingredient
(
GUID UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL,
Name NVARCHAR(#NVARCHARIndexSize) NOT NULL UNIQUE
)
Error:
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near '#NVARCHARIndexSize'
where line 13 is Name NVARCHAR(#NVARCHARIndexSize) NOT NULL UNIQUE.
Is there a way to use variables/functions instead of literals in a CREATE TABLE statement?
Thanks in advance.
You can create a custom type in SQL Server with following syntax
CREATE TYPE MyCustomType
FROM NVARCHAR(420);
And later on can use the custom type while creating tables
CREATE TABLE Ingredient
(
GUID UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL,
[Name] MyCustomType NOT NULL UNIQUE
)
DDL can't be parameterized. You'd have to use dynamic SQL for that. eg
DECLARE
#NVARCHARIndexSize INTEGER = dbo.[MAX NVARCHAR Index Size]()
declare #sql nvarchar(max) = concat('
CREATE TABLE Ingredient.Ingredient
(
GUID UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL,
Name NVARCHAR(',#NVARCHARIndexSize,') NOT NULL UNIQUE
)'
)
exec (#sql)
Prior to SQL Server 2016, the maximum key length was 900 bytes. MSDN Reference
Index Key Size
The maximum size for an index key is 900 bytes for a clustered index and 1,700 bytes for a nonclustered index. (Before
SQL Database and SQL Server 2016 (13.x) the limit was always 900
bytes.) Indexes on varchar columns that exceed the byte limit can be
created if the existing data in the columns do not exceed the limit at
the time the index is created; however, subsequent insert or update
actions on the columns that cause the total size to be greater than
the limit will fail. The index key of a clustered index cannot contain
varchar columns that have existing data in the ROW_OVERFLOW_DATA
allocation unit. If a clustered index is created on a varchar column
and the existing data is in the IN_ROW_DATA allocation unit,
subsequent insert or update actions on the column that would push the
data off-row will fail.
Nonclustered indexes can include non-key columns in the leaf level of
the index. These columns are not considered by the Database Engine
when calculating the index key size
You can define a NVARCHAR(450) column with check constraint, to ensure that your data does not go beyond 450 characters. I would suggest you to use DATALENGTH to ensure that column length is <= 900.
CREATE TABLE #test(id int identity(1,1) not null,
a NVARCHAR(500) CHECK (DATALENGTH(a) <= 900),
CONSTRAINT ak_a unique(a))
insert into #test
values('a') -- 1 row affected
insert into #test
values(REPLICATE('a',450)) -- 1 row affected
insert into #test
values(REPLICATE('a',451)) -- Error
Msg 547, Level 16, State 0, Line 12 The INSERT statement conflicted
with the CHECK constraint "CK__#test__________a__AC6651A7". The
conflict occurred in database "tempdb", table "#test", column 'a'.
In future, when you move to higher versions, you can increase length of NVARCHAR and CHECK constraint accordingly.

Postgres breaking null constraint on a serial column

I have a table that I create independently, the primary key is set with the serial type and a sequence applied to the table, but when I try to insert a value a NULL CONSTRAINT error is thrown and the return looks like null was passed, am I missing something in the INSERT statement?
SQL for table generation:
DROP TABLE IF EXISTS public."Team" CASCADE;
CREATE TABLE public."Team" (
"IdTeam" serial PRIMARY KEY,
name text NOT null,
CONSTRAINT "pKeyTeamUnique" UNIQUE ("IdTeam")
);
ALTER TABLE public."Team" OWNER TO postgres;
DROP SEQUENCE IF EXISTS public."Team_IdTeam_seq" CASCADE;
CREATE SEQUENCE public."Team_IdTeam_seq"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public."Team_IdTeam_seq" OWNER TO postgres;
ALTER SEQUENCE public."Team_IdTeam_seq" OWNED BY public."Team"."IdTeam";
SQL for insert :
INSERT INTO public."Team" (name) values ('Manchester Untited');
The returning error:
ERROR: null value in column "IdTeam" violates not-null constraint
DETAIL: Failing row contains (null, Manchester Untited).
SQL state: 23502
I am baffled. Why are you trying to define your own sequence when the column is already defined as serial?
Second, a primary key constraint is already unique. There is no need for a separate unique constraint.
Third, quoting identifiers just makes the code harder to write and to read.
You can just do:
DROP TABLE IF EXISTS public.Team CASCADE;
CREATE TABLE public.Team (
IdTeam serial PRIMARY KEY,
name text NOT null
);
INSERT INTO public.Team (name)
VALUES ('Manchester Untited');
Dropping the sequence causes the default definition for the IdTeam column to be dropped. After recreating the sequence you will have to recreate the default definition.

How do I select insert into select a table which already has values in the primary key column without adding new rows?

I'm working on a database for my school project in which I have to produce a functional database by normalizing sample tables given to us.
One table I'm having trouble with is itineraries. I produce 3 tables from the normalization which are "Destinations", "Itineraries" and "Itinerary_Destinations".
The code for Destinations is:
create table Destinations
(
DestinationID varchar(5) primary key,
Name varchar(45)
);
The code for Itineraries is:
create table Itineraries
(
ItineraryID varchar(5),
Name varchar(45)
);
The code for the last table is:
create table Itinerary_Destinations
(
DI varchar(5) primary key,
ItineraryID varchar(5) foreign key references Itineraries(ItineraryID),
Itinerary_Name varchar(45),
DestinationID varchar(5) foreign key references Destinations(DestinationID),
Destination_Name varchar(45)
);
Data has already been inserted into all 3 tables with the exception of 'Destination_Name' and 'Itinerary_Name' columns. The code I'm attempting to use is returning as error. The code is shown below.
insert into Itinerary_Destinations (Itinerary_name)
select Name from Itineraries where
Itineraries.ItineraryID = ItineraryID;
The error it returns is
Msg 515, Level 16, State 2, Line 1 Cannot insert the value NULL into
column 'DI', table 'DDDAssignment.dbo.Itinerary_Destinations'; column
does not allow nulls. INSERT fails. The statement has been terminated.
Is there a method to accomplish the task of inserting the Destination_Name and Itinerary_Name without creating new records that require primary keys?
Or should I do it manually?
If you want to modify records which already exist, then you should be using an UPDATE rather than an INSERT:
UPDATE a
SET Itinerary_name = b.Name
FROM Itinerary_Destinations a
INNER JOIN Itinerary_name b
ON a.ItineraryID = b.ItineraryID;
But, if you do have some data which is not already logically associated with the Itinerary_Destinations table, then using an insert is appropriate.
use coalesce funtion in case null it will insert blank string, as your column does not allow null value thats why you got that error in your query
insert into Itinerary_Destinations (Itinerary_name)
select coalesce(Name,' ') from Itineraries where
Itineraries.ItineraryID = ItineraryID;

How to add a new column and a constraint in one go?

I want to add a new column to an existing table.
I need it to emulate the enum type (in the way possible in SQL Server; with value constraints, that is).
The following doesn't work:
ALTER TABLE orders ADD [sent_to_panel] NVARCHAR(16) NULL;
ALTER TABLE orders WITH CHECK ADD CONSTRAINT [CK_orders] CHECK (([sent_to_panel]='invalidated' OR [sent_to_panel]='not_sent' OR [sent_to_panel]='sent'));
ALTER TABLE orders ADD CONSTRAINT [DF_orders_sent_to_panel] DEFAULT (N'not_sent') FOR [sent_to_panel];
ALTER TABLE orders CHECK CONSTRAINT [CK_orders];
I'm getting an error:
Msg 207, Level 16, State 1, Line 2
Invalid column name 'sent_to_panel'.
If I execute the first command on its own, though:
ALTER TABLE orders ADD [sent_to_panel] NVARCHAR(16) NULL;
The rest goes through.
So I suppose the problem is that the column isn't actually added yet (and thus not recognized by ADD CONSTRAINT) when trying to get it all done in one go.
The question is: how to make the script work properly?
CREATE TABLE a (
b int
);
ALTER TABLE a
ADD c nvarchar(16) NULL
, CONSTRAINT check_this CHECK (c IN ('invalidated', 'not_sent', 'sent'))
, CONSTRAINT defaultify DEFAULT ('not_sent') FOR c
;
ALTER TABLE a
CHECK CONSTRAINT check_this
;
DROP TABLE a;