I've seen some related posts on SO, but haven't been able to figure out what is happening here. I have a Database Project in Visual Studio 2013. Here is some code for a simple "Users" table:
CREATE TABLE [dbo].[Users]
(
[ID] BIGINT IDENTITY(1,1) NOT NULL,
[Name] NVARCHAR(50) NOT NULL,
[Email] NVARCHAR(256) NOT NULL,
[Password] BINARY(20) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([ID]),
CONSTRAINT [IX_Users_Email] UNIQUE ([Email]),
CONSTRAINT [CK_Users] CHECK ([dbo].[CheckUserIsValid]([Users].[Name], [Users].[Email]) = 1)
)
And here is the code for CheckUserIsValid:
CREATE FUNCTION [dbo].[CheckUserIsValid]
(
#name NVARCHAR(50),
#email NVARCHAR(256)
)
RETURNS BIT
WITH SCHEMABINDING
AS
BEGIN
IF #name = ''
OR #email = ''
OR EXISTS(SELECT 1
FROM [dbo].[BlockedEmails]
WHERE [dbo].[BlockedEmails].[Email] = #email)
OR EXISTS(SELECT 1
FROM [dbo].[ApprovalCodes]
WHERE [dbo].[ApprovalCodes].[Email] = #email)
RETURN 0
RETURN 1
END
Now, the weird part is that when I open the code files BEFORE building the project, VS does not show any errors. When I try to build it, the build fails and I get a couple of different errors:
SQL04121: Cannot find either column "dbo" or the user-defined function or aggregate "dbo.CheckUserIsValid", or the name is ambiguous. (this one is thrown on the Users table)
SQL00208: Invalid object name 'dbo.BlockedEmails'. (this one is thrown on the function)
I've read this may have something to do with how I am using a scalar function in my check constraint. Pretty stuck now though. Not sure what to try next.
UPDATE
So, if I leave the function unchanged, but change the table to:
CREATE TABLE [dbo].[Users]
(
[ID] BIGINT IDENTITY(1,1) NOT NULL,
[Name] NVARCHAR(50) NOT NULL,
[Email] NVARCHAR(256) NOT NULL,
[Password] BINARY(20) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([ID]),
CONSTRAINT [IX_Users_Email] UNIQUE ([Email])
)
GO
ALTER TABLE [dbo].[Users] ADD CONSTRAINT [CK_Users] CHECK ([dbo].[CheckUserIsValid]([Users].[Name], [Users].[Email]) = 1)
GO
then bizarrely it builds fine. What the heck?
Related
I have a table created like this:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
Now I want to be able to keep the history modification of this table, so I want to make it as temporal table. I know the script to create a temporal table, the final result should be:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
The easy way to do that is just delete the previous table, and recreate the table with the good schema.
However, I have a lot of information in my table, save the data and delete the table, recreate it and re-insert the data make me uncomfortable.
So if you have a solution to transform the first table in temporal table without the need to delete everything and recreate it, it should be a great help!
Create the new table address_user_new, insert the data, then use sp_rename to rename address_user to address_user_old and address_user_new to address_user. This can all be done in a transaction to ensure ensure that the transition is atomic and apparently-instantaneous. eg
if object_id('address_user') is not null
ALTER TABLE address_user SET ( SYSTEM_VERSIONING = OFF)
go
if object_id('address_user_new') is not null
ALTER TABLE address_user_new SET ( SYSTEM_VERSIONING = OFF)
go
drop table if exists address_user
drop table if exists address_user_history
drop table if exists address_user_new
drop table if exists address_user_old
go
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
go
CREATE TABLE address_user_new
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_address_user_new]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
go
set xact_abort on
begin transaction
insert into address_user_new(username,address,id)
select username,address,id
from address_user with (tablockx)
exec sp_rename 'address_user', 'address_user_old', 'OBJECT'
exec sp_rename 'PK_address_user', 'PK_address_user_old', 'OBJECT'
exec sp_rename 'address_user_new', 'address_user', 'OBJECT'
exec sp_rename 'PK_address_user_new', 'PK_address_user', 'OBJECT'
commit transaction
I'm not sure what I'm doing wrong, but I'm getting a foreign key references invalid table message telling me that dbo.ValueStream is an invalid table.
Edit: I originally posted my code in the incorrect order. Fixed in the edit to reflect the order it was done in SSMS
CREATE TABLE dbo.ValueStream
(
ValueStreamKey int IDENTITY(1,1) NOT NULL
CONSTRAINT PK_ValueStream_ValueStreamKey PRIMARY KEY,
ValueStream nvarchar(20),
)
CREATE TABLE dbo.NonConformance
(
NonConformanceKey int IDENTITY(1,1) NOT NULL
CONSTRAINT PK_NonConformance_NonConformanceKey PRIMARY KEY,
CustomerVendorKey int NOT NULL
CONSTRAINT FK_NonConformance_CustomerVendorKey_CustomerVendor_CustomerVendorKey
FOREIGN KEY REFERENCES dbo.CustomerVendor(CustomerVendorKey),
ValueStreamKey int NOT NULL
CONSTRAINT FK_NonConformance_ValueStream_Key_ValueStream_ValueStreamKey
FOREIGN KEY REFERENCES dbo.ValueStream(ValueStreamKey),
RepairOrder nvarchar(50) NOT NULL,
WorkOrder nvarchar(8) NOT NULL,
PartNumber nvarchar(50) NOT NULL,
SerialNumber nvarchar(50) NOT NULL,
PartDescription nvarchar(50) NOT NULL,
InductionDate datetime NOT NULL,
TriageStartDate datetime NOT NULL,
TriageCompletionDate datetime NOT NULL,
RequiresRRCA Bit NOT NULL,
NonConformanceSummary nvarchar(max) NOT NULL
);
taking out the CONSTRAINT FK_NonConformance_CustomerVendorKey_CustomerVendor_CustomerVendorKey
FOREIGN KEY REFERENCES dbo.CustomerVendor(CustomerVendorKey)
(we don't have that one)
and running the scripts seperately - first the first table and then the creation of the referencing table - this works for me.
No code errors.
You are creating dbo.NonConformance first in the script that you have posted. You need to move the CREATE TABLE dbo.ValueStream statement so that it is created first, ensuring there is a GO statement still between the two CREATE TABLE statements.
As it stands you are trying to create a foreign key to a table that does not exist.
I'm working on an assignment and have created my code on NotePad++ to then copy over to SSMS, however when I create a table it brings me to the default view which is manually entering the column names and data. I want to just paste my created code into the database to create the table. How do I go about this?
Also my prof has provided data to populate my tables but I can't seem to figure out where I paste his INSERT INTO data into?
Also, for some reason I attempted to create a new query in the database i created for the assignment and pasted the code into that, but the tables don't show up even if I execute them in the Tables drop down.
Code for notepad++
CREATE TABLE tblMajors
(
MajorCode varchar(10) PRIMARY KEY NOT NULL,
MajorDescription varchar(MAX) NOT NULL,
)
CREATE TABLE tblInstructors
(
InstructorNumber int PRIMARY KEY NOT NULL,
InstructorFirst varchar(50) NOT NULL,
InstructorLast varchar(50) NOT NULL,
ContractStatus varchar(10) NOT NULL,
PhoneNumber bigint NOT NULL,
)
CREATE TABLE tblStudents
(
StudentNumber int PRIMARY KEY NOT NULL,
StudentFirst varchar(20) NOT NULL,
StudentLast varchar(20) NOT NULL,
MajorCode varchar(10) FOREIGN KEY REFERENCES tblMajors (MajorCode),
)
CREATE TABLE tblCourses
(
CourseCode varchar(10) PRIMARY KEY NOT NULL,
CourseDescription varchar(MAX) NOT NULL,
)
CREATE TABLE tblGrades
(
StudentNumber bigint FOREIGN KEY REFERENCES tblStudents (StudentNumber),
CourseCode varchar(10) FOREIGN KEY REFERENCES tblCourses (CourseCode),
Grade int NOT NULL,
IntructorNumber int FOREIGN KEY REFERENCES tblInstructors (IntructorNumber),
PRIMARY KEY (StudentNumber, CourseCode)
)
I try to use SQL Server Temporal Tables within Visual Studio 2017 and SQL Server Data Tools (SSDT).
But I get immediately following error:
SQL71609: System-versioned current and history tables do not have
matching schemas. Mismatched column: '[dbo].[MyTable].[ValidFrom]'
I don't see any mistake. Do I miss something?
I created a small repository on GIT HUB for reproduction
The current table is defined as:
CREATE TABLE [dbo].[MyTable]
(
[TenantId] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_MyTable_TenantId] DEFAULT
CAST(SESSION_CONTEXT(N'TenantId') AS UNIQUEIDENTIFIER),
[Rn] BIGINT IDENTITY(1,1) NOT NULL,
[Id] UNIQUEIDENTIFIER NOT NULL,
[PropA] INT NOT NULL,
[PropB] NVARCHAR(100) NOT NULL,
[ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL CONSTRAINT [DF_ValidFrom] DEFAULT CONVERT(DATETIME2, '0001-01-01'),
[ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL CONSTRAINT [DF_ValidTo] DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'),
PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]),
CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED ([Id]),
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[MyTableHistory]))
GO
CREATE UNIQUE CLUSTERED INDEX [CIX_MyTable] ON [dbo].[MyTable]([Rn])
GO
And the history table :
CREATE TABLE [dbo].[MyTableHistory]
(
[TenantId] UNIQUEIDENTIFIER NOT NULL,
[Rn] BIGINT IDENTITY(1,1) NOT NULL,
[Id] UNIQUEIDENTIFIER NOT NULL,
[PropA] INT NOT NULL,
[PropB] NVARCHAR(100) NOT NULL,
[ValidFrom] DATETIME2,
[ValidTo] DATETIME2,
);
GO
CREATE CLUSTERED COLUMNSTORE INDEX [COLIX_MyTableHistory]
ON [dbo].[MyTableHistory];
GO
CREATE NONCLUSTERED INDEX [IX_ImpactHistory_ValidFrom_ValidTo_Id]
ON [dbo].[MyTableHistory] ([ValidFrom], [ValidTo], [Id]);
GO
Not really sure why you are getting this particular error message.
I've tested your code on db fiddle and got different errors.
BTW, please note that you don't have to write the history table yourself - if you only set it's name using the SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[MyTableHistory]) and not create it, SQL Server will generate it automatically for you - as can be seen in this fiddle.
For the first attempt I've got this error:
Msg 13518 Level 16 State 1 Line 20
Setting SYSTEM_VERSIONING to ON failed because history table 'fiddle_e3d361da65804a39b041c8149132b443.dbo.MyTableHistory' has IDENTITY column specification. Consider dropping all IDENTITY column specifications and trying again.
So I've removed the identity from [Rn] column in the history table and tried again.
Then I've got this error:
Msg 13530 Level 16 State 1 Line 20
Setting SYSTEM_VERSIONING to ON failed because system column 'ValidFrom' in history table 'fiddle_d6660ab11cdc448dba35790867169a14.dbo.MyTableHistory' corresponds to a period column in table 'fiddle_d6660ab11cdc448dba35790867169a14.dbo.MyTable' and cannot be nullable.
So I've changed both the ValidFrom and ValidTo columns to NOT NULL and finally got it working.
The working version is copied to here:
CREATE TABLE [dbo].[MyTableHistory]
(
[TenantId] UNIQUEIDENTIFIER NOT NULL,
[Rn] BIGINT NOT NULL,
[Id] UNIQUEIDENTIFIER NOT NULL,
[PropA] INT NOT NULL,
[PropB] NVARCHAR(100) NOT NULL,
[ValidFrom] DATETIME2 NOT NULL,
[ValidTo] DATETIME2 NOT NULL,
);
CREATE CLUSTERED COLUMNSTORE INDEX [COLIX_MyTableHistory]
ON [dbo].[MyTableHistory];
CREATE NONCLUSTERED INDEX [IX_ImpactHistory_ValidFrom_ValidTo_Id]
ON [dbo].[MyTableHistory] ([ValidFrom], [ValidTo], [Id]);
CREATE TABLE [dbo].[MyTable]
(
[TenantId] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_MyTable_TenantId] DEFAULT CAST(SESSION_CONTEXT(N'TenantId') AS UNIQUEIDENTIFIER),
[Rn] BIGINT IDENTITY(1,1) NOT NULL,
[Id] UNIQUEIDENTIFIER NOT NULL,
[PropA] INT NOT NULL,
[PropB] NVARCHAR(100) NOT NULL,
[ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL CONSTRAINT [DF_ValidFrom] DEFAULT CONVERT(DATETIME2, '0001-01-01'),
[ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL CONSTRAINT [DF_ValidTo] DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'),
PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]),
CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED ([Id]),
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[MyTableHistory]))
CREATE UNIQUE CLUSTERED INDEX [CIX_MyTable] ON [dbo].[MyTable]([Rn])
I am seeing intermittent failures upon a simple delete.
Essentially I have a temporary note that has many entries. Each entry has a classification which is a lookup value. Once this note is completed, it gets sent to a note repository, and the temporary version needs to be deleted.
I can't replicate reliably, but on occasion, when calling the stored procedure that does the delete of the temp note, only SOME of the entries get deleted. Coincidentally (?) the entry left behind has always been of one specific classification type.
After many many many attempts I was able to reproduce the issue while running SQL Server Profiler. Despite trying to catch Attention, ErrorLog, EventLog, Exception, and Execution Warnings, the resulting profile shows nothing out of the ordinary.
None of the involved tables are large. In fact they're minuscule. ~100-1000 at any given time in Entry, ~100 in Draft, 9 in Classification, 3 in Category.
I don't believe it should matter, but just in case, this stored procedure is being called from Entity Framework.
Any ideas? Any ideas on what to try for troubleshooting? I'm completely at a loss. Thanks in advance for any help.
Here is the stored procedure for deletion:
CREATE PROCEDURE [NoteDraft].[ClearNoteDraft]
#DraftId BIGINT
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM NoteDraft.[Entry]
WHERE DraftId = #DraftId
DELETE FROM NoteDraft.Draft
WHERE Id = #DraftId
END
Here are the table definitions (with some columns left out for brevity as noted.)
CREATE TABLE [NoteDraft].[Category]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[SortOrder] [int] NULL,
CONSTRAINT [PK_Category]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
CREATE TABLE [NoteDraft].[Classification]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[CategoryId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[SortOrder] [int] NULL,
CONSTRAINT [PK_Classification]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
CREATE TABLE [NoteDraft].[Draft]
(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[DateModified] [datetime] NOT NULL CONSTRAINT [DF_TestNoteDraft_DateModified] DEFAULT (getdate()),
[AccountNumber] [varchar](30) NULL,
--...10 other biz columns...
CONSTRAINT [PK_Notes]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
CREATE TABLE [NoteDraft].[Entry]
(
[DraftId] [bigint] NOT NULL,
[ClassificationId] [int] NOT NULL,
[Body] [varchar](2100) NULL,
CONSTRAINT [PK_Entry]
PRIMARY KEY CLUSTERED ([DraftId] ASC, [ClassificationId] ASC)
) ON [PRIMARY]
ALTER TABLE [NoteDraft].[Classification] WITH CHECK
ADD CONSTRAINT [FK_Classification_Category]
FOREIGN KEY([CategoryId]) REFERENCES [NoteDraft].[Category] ([Id])
GO
ALTER TABLE [NoteDraft].[Classification] CHECK CONSTRAINT [FK_Classification_Category]
GO
ALTER TABLE [NoteDraft].[Entry] WITH CHECK
ADD CONSTRAINT [FK_Entry_Classification]
FOREIGN KEY([ClassificationId]) REFERENCES [NoteDraft].[Classification] ([Id])
GO
ALTER TABLE [NoteDraft].[Entry] CHECK CONSTRAINT [FK_Entry_Classification]
GO
ALTER TABLE [NoteDraft].[Entry] WITH CHECK
ADD CONSTRAINT [FK_Entry_Draft]
FOREIGN KEY([DraftId]) REFERENCES [NoteDraft].[Draft] ([Id])
GO
ALTER TABLE [NoteDraft].[Entry] CHECK CONSTRAINT [FK_Entry_Draft]
GO
As with everything simple like this, the answer wasn't where I was looking.
Turns out, there's an event listener on the page that's re-inserting the records post deletion.
Still having trouble figuring out why the listener is running, but at least I know what's going on.