Declaring a default constraint when creating a table - tsql

I am creating a new table in Microsoft SQL server 2000 by writing the code instead of using the GUI, I am trying to learn how to do it "the manual way".
This is the code I am actually using, and it works fine:
CREATE TABLE "attachments"
(
"attachment_id" INT NOT NULL,
"load_date" SMALLDATETIME NOT NULL,
"user" VARCHAR(25) NOT NULL,
"file_name" VARCHAR(50) NOT NULL,
CONSTRAINT "pk_attachments" PRIMARY KEY ("attachment_id"),
CONSTRAINT "fk_users" FOREIGN KEY ("user") REFERENCES "users" ("user"),
CONSTRAINT "ch_load_date" CHECK ("load_date" < GETDATE())
)
I have specified the primary key, foreign key and check constraints on their own because in this way I can define a name for them, otherwise declaring them inline would make SQL Server generate a random name, and I do not "like" it.
The problem arose when I tried to declare the default value constraint: looking at the informations on the internet and how Microsoft SLQ Server Management Studio creates it, I understood that it can be created both inline and on its own:
"load_date" SMALLDATETIME NOT NULL DEFAULT GETDATE()
or
CONSTRAINT "df_load_date" DEFAULT GETDATE() FOR "load_date"
The inline method works fine, but it generates as usual a random name for the constaint, the stand alone method throws an error, saying Incorrect syntax near 'FOR'..
Also, if I create the table and then ALTER it, the command works:
ALTER TABLE "attachments"
ADD CONSTRAINT "df_load_date" DEFAULT GETDATE() FOR "load_date"
As a reference, here is the full code I am trying to execute:
CREATE TABLE "attachments"
(
"attachment_id" INT NOT NULL,
"load_date" SMALLDATETIME NOT NULL,
"user" VARCHAR(25) NOT NULL,
"file_name" VARCHAR(50) NOT NULL,
CONSTRAINT "pk_attachments" PRIMARY KEY ("attachment_id"),
CONSTRAINT "fk_users" FOREIGN KEY ("user") REFERENCES "users" ("user"),
CONSTRAINT "ch_load_date" CHECK ("load_date" < GETDATE()),
CONSTRAINT "df_load_date" DEFAULT GETDATE() FOR "load_date"
)
I'm totally at loss here, is what I am trying to do not possible, or I am doing something wrong?
Edit:
David M showed how to add a named default constraint using the inline syntax, I am still looking to understand if the stand alone syntax is completely wrong or it is my fault.

Do it inline with the column creation:
[load_date] SMALLDATETIME NOT NULL
CONSTRAINT [df_load_date] DEFAULT GETDATE()
I have used square brackets rather than quotes as many readers won't work with QUOTED_IDENTIFIERS on by default.

Related

Entity Framework won't detect foreign key from database

I've got two tables - Appointment and User. Appointments can be linked to two different Users - a student and a member of staff. The Appointment table contains two foreign keys: StaffUsername and ExternalID. These reference columns in the User table named Username (the User table's PK) and ExternalID (a UNIQUE index). Here are the table definitions:
CREATE TABLE [dbo].[Appointment]
(
[ID] INT NOT NULL IDENTITY(1,1),
[AppointmentTypeID] INT NOT NULL,
[StartTime] DATETIME NOT NULL,
[EndTime] DATETIME NOT NULL,
[AppointmentSlotID] INT NULL,
[StaffUsername] NVARCHAR(200) NOT NULL,
[ExternalID] NVARCHAR(10) NULL,
[BookedBy] NVARCHAR(200) NOT NULL,
[BookedTimestamp] DATETIME NOT NULL,
[ReminderEmailSentTimestamp] DATETIME NULL,
[CancelledBy] NVARCHAR(200) NULL,
[CancelledTimestamp] DATETIME NULL,
[StudentDidNotAttend] BIT NULL,
[LastModifiedTimestamp] DATETIME NOT NULL,
[LastModifiedBy] NVARCHAR(200) NOT NULL,
CONSTRAINT [PK_Appointment] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_Appointment_AppointmentType] FOREIGN KEY ([AppointmentTypeID]) REFERENCES [dbo].[AppointmentType]([ID]),
CONSTRAINT [FK_Appointment_AppointmentSlot] FOREIGN KEY ([AppointmentSlotID]) REFERENCES [dbo].[AppointmentSlot]([ID]),
CONSTRAINT [FK_Appointment_User_StaffUsername] FOREIGN KEY ([StaffUsername]) REFERENCES [dbo].[User]([Username]),
CONSTRAINT [FK_Appointment_User_ExternalID] FOREIGN KEY ([ExternalID]) REFERENCES [dbo].[User]([ExternalID])
)
CREATE TABLE [dbo].[User]
(
[Username] NVARCHAR(200) NOT NULL,
[FirstName] NVARCHAR(200) NULL,
[LastName] NVARCHAR(200) NULL,
[EmailAddress] NVARCHAR(200) NULL,
[IsStaff] BIT NOT NULL DEFAULT 0,
[ExternalID] NVARCHAR(10) NOT NULL,
[LastLogin] DATETIME NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Username] ASC),
CONSTRAINT [UQ_ExternalID] UNIQUE ([ExternalID])
)
Unfortunately, when I use the Update model from database option in the EDMX model designer, it will not pick up the foreign key on the ExternalID columns. It remains looking like this (highlighted in green are the properties relating to the relationship which is modelled correctly, in yellow are the properties which should relate to a second relationship but are being ignored):
I know from experience that the EDMX designer can be quirky at times, especially when detecting changes to objects, so I've tried all the usual tricks. I've checked in Web.config that my connection string is pointing to the correct database. I've deleted the Appointment and User tables in the designer completely and run the Update command again. I've tried that with a save and restart of Visual Studio between deletion and update, too.
To check the relationship is correct in the database I've created a database diagram in SSMS which shows the troublesome relationship correctly:
I've also created a brand new project and added a new Entity Data Model pointing to the same database with the same credentials, just in case the issue was related to the fact that I'm updating an existing model, but no dice. Even in the new project, the relationship isn't detected.
I also tried to create the Navigation Property manually, but as you can see from this screenshot, the foreign key I'd need to select isn't available in the dropdown list:
I don't know if the issue somehow relates to the fact that the ExternalID column isn't the primary key of the User table, or maybe its NVARCHAR(10) data type. I've no idea, to be honest.
Any suggestions as to why this foreign key isn't being detected? And how I can fix it? My project targets .NET Framework 4.6 and I'm using EF6. Obviously I'm using Database First.
In EF6 an Entity only has one key, and so all Navigation Properties must use a Foreign Key that references the same key. EF Core supports Alternate Keys, and supports a Database-First workflow with Reverse Engineering.

How do I create a check to make sure a value exists in another table?

Right now I have two tables, one that contains a compound primary key and another that that references one of the values of the primary key but is a one-to-many relationship between Product and Mapping. The following is an idea of the setup:
CREATE TABLE dev."Product"
(
"Id" serial NOT NULL,
"ShortCode" character(6),
CONSTRAINT "ProductPK" PRIMARY KEY ("Id")
)
CREATE TABLE dev."Mapping"
(
"LookupId" integer NOT NULL,
"ShortCode" character(6) NOT NULL,
CONSTRAINT "MappingPK" PRIMARY KEY ("LookupId", "ShortCode")
)
Since the ShortCode is displayed to the user as a six character string I don't want to have a another table to have a proper foreign key reference but trying to create one with the current design is not allowed by PostgreSQL. As such, how can I create a check so that the short code in the Mapping table is checked to make sure it exists?
Depending on the fine print of your requirements and your version of Postgres I would suggest a TRIGGER or a NOT VALID CHECK constraint.
We have just discussed the matter in depth in this related question on dba.SE:
Disable all constraints and table checks while restoring a dump
If I understand you correctly, you need a UNIQUE constraint on "Product"."ShortCode". Surely it should be declared NOT NULL, too.
CREATE TABLE dev."Product"
(
"Id" serial NOT NULL,
"ShortCode" character(6) NOT NULL UNIQUE,
CONSTRAINT "ProductPK" PRIMARY KEY ("Id")
);
CREATE TABLE dev."Mapping"
(
"LookupId" integer NOT NULL,
"ShortCode" character(6) NOT NULL REFERENCES dev."Product" ("ShortCode"),
CONSTRAINT "MappingPK" PRIMARY KEY ("LookupId", "ShortCode")
);
Your original "Product" table will allow this INSERT statement to succeed, but it shouldn't.
insert into dev."Product" ("ShortCode") values
(NULL), (NULL), ('ABC'), ('ABC'), ('ABC');
Data like that is just about useless.
select * from dev."Product"
id ShortCode
--
1
2
3 ABC
4 ABC
5 ABC

PostgreSQL tables creation with wrong order

I have an .sql file, that creates lots of tables, that are related to each other.
I made other file for testing, that holds only two statements:
CREATE TABLE "USER" (
"id" bigint NOT NULL,
"name" varchar(50),
PRIMARY KEY ("id"));
CREATE TABLE "PERSON" (
"id" bigint NOT NULL,
"name" varchar(50),
"user" bigint,
PRIMARY KEY ("id"),
CONSTRAINT "fk_user" FOREIGN KEY ("user") REFERENCES "USER" ("id"));
This works fine if i'm trying to execute such file, but if i have other order - where table "PERSON" is created first - i'm getting ERROR: relation "USER" does not exist.
Is it possible to make some changes (or use some additional options when running 'psql' command), leaving the order as it is, to make it work?
EDIT: I understand why this error happens in given case, but i was thinking about some solution, where i don't need to change the order of my CREATE statements (Imagine you have hundreds of tables)... In MySQL you can simply use SET FOREIGN_KEY_CHECKS=0; and this will work. Do i have similar possibilities in PostgreSQL?
If you want table a to reference table b, you must either create table b before table a, or add the foreign key reference after creation:
ALTER TABLE a ADD FOREIGN KEY (a_col) REFERENCES b(b_col);
That works to create two tables that reference each other, too, but you won't be able to create rows unless you make one of them DEFERRABLE INITIALLY DEFERRED.
You are getting the error because at the point you are creating the foreign key on the the PERSON table it references the USER table which does not exist yet.
You can work round this issue by separating out FOREIGN KEY CONSTRAINT into it's own statement and applying this after you have created both tables:
CREATE TABLE "PERSON" (
"id" bigint NOT NULL,
"name" varchar(50),
"user" bigint,
PRIMARY KEY ("id"));
CREATE TABLE "USER" (
"id" bigint NOT NULL,
"name" varchar(50),
PRIMARY KEY ("id"));
ALTER TABLE "PERSON"
ADD CONSTRAINT fk_user
FOREIGN KEY ("user")
REFERENCES "USER" (id);

PostgreSQL: NULL value in foreign key column

In my PostgreSQL database I have the following tables (simplified):
CREATE TABLE quotations (
receipt_id bigint NOT NULL PRIMARY KEY
);
CREATE TABLE order_confirmations (
receipt_id bigint NOT NULL PRIMARY KEY
fk_quotation_receipt_id bigint REFERENCES quotations (receipt_id)
);
My problem now reads as follows:
I have orders which relate to previous quotations (which is fine 'cause I can attach such an order to the quotation referenced by using the FK field), but I also have placed-from-scratch orders without a matching quotation. The FK field would then be NULL, if the database let me, of course. Unfortunately, I get an error when trying to set fk_quotation_receipt_id to NULL in an INSERT statement because of a violated foreign key constraint.
When designing these tables I was still using PgSQL 8.2, which allowed NULL values. Now I've got 9.1.6, which does not allow for this.
What I wish is an optional (or nullable) foreign key constraint order_confirmations (fk_quotation_receipt_id) → quotations (receipt_id). I can't find any hints in the official PgSQL docs, and similar issues posted by other users are already quite old.
Thank you for any useful hints.
Works for me in 9.3 after correcting a missing comma. I'm sure it will work also in 9.1
create table quotations (
receipt_id bigint not null primary key
);
create table order_confirmations (
receipt_id bigint not null primary key,
fk_quotation_receipt_id bigint references quotations (receipt_id)
);
insert into order_confirmations (receipt_id, fk_quotation_receipt_id) values
(1, null);
Confirmation will include:
INSERT 0 1

postgresql unique constraint not unique enough

I am creating tables to handle the security question/selected question/given answer section of our database and getting this error:
there is no unique constraint matching given keys for referenced table "m_security_questions"
Not sure how I fix this?
(Since schema won't build b/c of error, I couldn't add SQL Fiddle)
CREATE TABLE security_question --defines questions
(
id SERIAL PRIMARY KEY NOT NULL,
question character varying(1024) NOT NULL,
is_custom boolean DEFAULT FALSE NOT NULL
);
INSERT INTO security_question
(question,is_custom)
VALUES
('do you know the answer?',FALSE),
('Write your own question',TRUE);
CREATE TABLE m_security_questions
( --defines question a member chooses & allows free form question
-- id SERIAL NOT NULL,
-- I know adding id like this and making keeping same pk solves it
-- but isn't storing the extra sequence not needed?
member integer --REFERENCES member(m_no)
-- commented out reference for so only
NOT NULL,
question integer REFERENCES security_question(id) NOT NULL,
m_note text,
PRIMARY KEY(member,question)
);
-- here I add unique constraint but doesn't the primary already mean I have a unique index?
ALTER TABLE m_security_questions ADD CONSTRAINT m_security_questions_unique_member_question UNIQUE (member,question);
INSERT INTO m_security_questions
(member,question,m_note)
VALUES
(2,1,NULL),
(2,2,'How many marbles in this jar?');
CREATE TABLE m_security_answer --defines members given answer
( -- I want member & question here to line up w/ same from m_security_questions
member integer REFERENCES m_security_questions(member),
question integer REFERENCES m_security_questions(question) NOT NULL,
answer character varying(255) NOT NULL,
PRIMARY KEY (member,question)
);
-- here is where I get the error:
-- there is no unique constraint matching given keys for referenced table "m_security_questions"
INSERT INTO m_security_answer
(member,question,answer)
VALUES
(2,1,'yes'),
(2,2,'431');
The primary key definitely defines a unique constraint. But the unique constraint is on (member,question). Your have two FOREIGN KEY constraints that references just (member) and (question) separately.
I'm pretty sure what you want is:
CREATE TABLE m_security_answer --defines members given answer
(
member integer,
question integer NOT NULL,
answer character varying(255) NOT NULL,
PRIMARY KEY (member,question),
FOREIGN KEY (member, question) REFERENCES m_security_questions(member, question)
);