My table definition:
CREATE TABLE [dbo].[Action](
[ActionId] [int] IDENTITY(1,1) NOT NULL,
[ActionType] [nvarchar](50) NOT NULL,
[Initiator] [nvarchar](256) NOT NULL,
[Date] [datetime] NOT NULL,
CONSTRAINT [PK_Action] PRIMARY KEY CLUSTERED
(
[ActionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Code I try to execute:
create trigger delete_on_titles on titles
after delete
as
begin
insert into Action (ActionType, Initiator, Date) values ('Add', USER_NAME(), getdate());
declare #id int = ##identity;
insert into Old_titles select * from deleted
update Old_titles set ActionId = #id where ActionId is null
end
But I get the error:
Msg 213, Level 16, State 1, Procedure delete_on_titles, Line 15 [Batch Start Line 2]
Column name or number of supplied values does not match table definition.
at the line "insert into Action (ActionType, Initiator, Date) values ('Add', USER_NAME(), getdate());"
What am I doing wrong?
UPDATED:
Thanks to #Larnu. Yes, the problem was in the line:
insert into Old_titles select * from deleted
I changed it to:
insert into Old_titles (
title_id, title, type, pub_id, price,
advance, royalty, ytd_sales, notes, pubdate)
select * from deleted
where title_id, title, type, pub_id, price, advance, royalty, ytd_sales, notes, pubdate are columns of the table deleted, and it works.
I'm performing a cascading insert in a SQL Server stored procedure. Then I pass the SCOPE_IDENTITY from the ID of the first table insert to the second table.
But during executing the stored procedure I get a NULL value for the SCOPE_IDENTITY:
Msg 515, Level 16, State 2, Procedure InsertDDM_UserProfile, Line 43
Cannot insert the value NULL into column 'Filter', table '.....dbo.DDM_Dashboard'; column does not allow nulls. INSERT fails.
Question: why does the stored procedure return a null ID using SCOPE_IDENTITY?
This is the stored procedure I've drafted. FK constraints have already been set up for the tables:
ALTER PROCEDURE [dbo].[InsertDDM_UserProfile]
#p_email VARCHAR(100),
#p_dashboardName VARCHAR(100),
AS
BEGIN
INSERT INTO [dbo].[DDM_User] ([Email])
VALUES (#p_email)
INSERT INTO [dbo].[DDM_Dashboard] ([Dashboard_Name], [DDM_USER_ID])
VALUES (#p_dashboardName, SCOPE_IDENTITY())
END
And below are the two table's structure:
DDM_User-
CREATE TABLE [dbo].[DDM_User]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Email] [varchar](80) NOT NULL,
CONSTRAINT [PK_DDMUser]
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
DDM_Dashboard:
CREATE TABLE [dbo].[DDM_Dashboard]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Dashboard_Name] [varchar](100) NOT NULL,
[DDM_USER_ID] [int] NOT NULL,
CONSTRAINT [PK_DDMDashboard]
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DDM_Dashboard] WITH NOCHECK
ADD CONSTRAINT [FK_DDMDashboard_DDMUser]
FOREIGN KEY([DDM_USER_ID]) REFERENCES [dbo].[DDM_User] ([ID])
GO
ALTER TABLE [dbo].[DDM_Dashboard] CHECK CONSTRAINT [FK_DDMDashboard_DDMUser]
GO
This is nothing to do with SCOPE_IDENTITY(), during your second insert:
INSERT INTO [dbo].[DDM_Dashboard] ([Dashboard_Name], [DDM_USER_ID])
VALUES (#p_dashboardName, SCOPE_IDENTITY())
You are only inserting into two columns [Dashboard_Name], and [DDM_USER_ID]. You do not specify a value for the column [Filter], which from your error message does not allow null values, therefore your insert fails.
DECLARE #Value1 varchar(50) = 'Test1', #Value2 varchar(50) = 'Test2';
DECLARE #Table1 table (Id int NOT NULL IDENTITY(1,1), Value varchar(50) NOT NULL);
DECLARE #Table2 table (Id int NOT NULL, Value varchar(50) NOT NULL);
INSERT INTO #Table1 (Value1)
OUTPUT inserted.Id, #Value2 INTO #Table2 (Id, Value)
Values (#Value1)
;
SELECT * FROM #Table1;
SELECT * FROM #Table1;
edit:
As GarethD pointed out, this is not actually a valid solution to your problem due to the foreign key constraint. However in other scenarios this is a useful way to handle cascading inserts and updates as it is an atomic operation of both records.
I have a system-versioning table with history table related as follows:
CREATE TABLE [dbo].[ExpenseCenter_Archive](
[ExpenseCenterId] [tinyint] NOT NULL,
[Name] [nvarchar](200) NOT NULL,
[LineCode] [smallint] NOT NULL,
[SysStartTime] [datetime2](2) NOT NULL,
[SysEndTime] [datetime2](2) NOT NULL
) ON [FG_HISTORY]
GO
-------
CREATE TABLE [dbo].[ExpenseCenter](
[ExpenseCenterId] [tinyint] NOT NULL,
[Name] [nvarchar](200) NOT NULL,
[LineCode] [smallint] NOT NULL,
[SysStartTime] [datetime2](2) GENERATED ALWAYS AS ROW START NOT NULL,
[SysEndTime] [datetime2](2) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_ExpenseCenter] PRIMARY KEY CLUSTERED
(
[ExpenseCenterId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [FG_DATA],
CONSTRAINT [UK_ExpenseCenterName] UNIQUE NONCLUSTERED
(
[Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [FG_INDEX],
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [FG_DATA]
WITH
(
SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[ExpenseCenter_Archive] , DATA_CONSISTENCY_CHECK = ON )
)
GO
Now, I want alter data type of 'LineCode' in system-version table and history. After changes once again enabling it as follows:
--- Before edit column
ALTER TABLE [dbo].[ExpenseCenter] SET (SYSTEM_VERSIONING = OFF);
-- ## Edit column in ssms ##
--- After edit column
ALTER TABLE [dbo].[ExpenseCenter]
SET
(
SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[ExpenseCenter_Archive])
);
But I get the following error:
Cannot set SYSTEM_VERSIONING to ON when SYSTEM_TIME period is not defined.
How do I solve this issue.
From your question ,you are saying that ExpenseCenter_archive is the temporal table for ExpenseCenter..but error message says
you don't have system versioned table [dbo].[ExpenseCenter] ,if you want system versioned table ,Add system_time to it
so here are the steps,i would follow to make a table Temporal table of other..
if its for a new table ..
CREATE TABLE Department
(
DeptID int NOT NULL PRIMARY KEY CLUSTERED
, DeptName varchar(50) NOT NULL
, ManagerID INT NULL
, ParentDeptID int NULL
, SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
, SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
, PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON)
;
if i need to alter data type for this newly created table..
MSDN recommends doing it in a transaction..
BEGIN TRAN
ALTER TABLE [dbo].[CompanyLocation] SET (SYSTEM_VERSIONING = OFF);
ALTER TABLE [CompanyLocation] ADD Cntr INT IDENTITY (1,1);
ALTER TABLE [dbo].[CompanyLocation]
SET
(
SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[CompanyLocationHistory])
);
COMMIT ;
If i want to make an existing table Temporal,then i would do like below
ALTER TABLE dbo.Product
ADD StartTime DATETIME2 GENERATED ALWAYS AS ROW START
HIDDEN DEFAULT GETUTCDATE(),
EndTime DATETIME2 GENERATED ALWAYS AS ROW END
HIDDEN DEFAULT
CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'),
PERIOD FOR SYSTEM_TIME (StartTime, EndTime)
Now finally set Temporal ON
ALTER TABLE dbo.Product
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE=dbo.ProductHistory))
GO
References:
http://sqlhints.com/tag/modify-existing-table-as-system-versioned-temporal-table/
https://msdn.microsoft.com/en-us/library/mt590957.aspx
for alter system versioning table you don't need set SYSTEM_VERSIONING = OFF, but directly use ALTER TABLE ...
SCENARIO
I need to select records from test_userData based on a 1-to-1 match from test_userCheck on the columns customer or account_info. The code below will create a mock-up of the tables and will populate with random data for the purpose of my question. Based on this code, it's looking for any records where test_userData.customer = 'Guerrero, Unity' or test_userData.account_info = 'XXXXXXXXXXXXXXXX0821', and should return three rows (confirmation_id = 6836985, 5502798, and 3046441)
PROBLEM
As it stands, the query returns what I need... however, my real userData table has almost 2 million records, and the userCheck table has about 10,000. The query takes about 7 seconds as it is and I think that's way too long. I'm also worried because the userData table will start to grow quickly (by tens of thousands of unique records a day), and I envision my current method becoming unmanageable.
QUESTION
Any ideas on how I can optimize this to scale with millions of records? The data resides on a shared SQL 2008 server with limited permissions.
--setup temporary testing tables
IF EXISTS
(
SELECT * FROM dbo.sysobjects
WHERE id = object_id(N'[dbo].[test_userData]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1
)
DROP TABLE [dbo].[test_userData]
GO
IF EXISTS
(
SELECT * FROM dbo.sysobjects
WHERE id = object_id(N'[dbo].[test_userCheck]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1
)
DROP TABLE [dbo].[test_userCheck]
GO
CREATE TABLE [dbo].[test_userData](
[id] [int] IDENTITY(1,1) NOT NULL,
[merchant_id] [int] NOT NULL,
[sales_date] [datetime] NOT NULL,
[confirmation_id] [int] NOT NULL,
[customer] [nvarchar](max) NOT NULL,
[total] [smallmoney] NOT NULL,
[account_info] [nvarchar](max) NOT NULL,
[email_address] [nvarchar](max) NOT NULL
CONSTRAINT [PK_test_userData] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[test_userCheck](
[confirmation_id] [int] NOT NULL,
[customer] [nvarchar](max) NOT NULL,
[total] [smallmoney] NOT NULL,
[account_info] [nvarchar](max) NOT NULL
CONSTRAINT [PK_test_userCheck] PRIMARY KEY CLUSTERED
(
[confirmation_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--insert some random user transactions
INSERT INTO [dbo].[test_userData] (merchant_id,sales_date,confirmation_id,customer,total,account_info,email_address) VALUES
('99','03/25/2010','3361424','Soto, Ahmed','936','XXXXXXXXXXXXXXXX8744','Donec.egestas#NullainterdumCurabitur.ca'),
('17','09/12/2010','6710165','Holcomb, Eden','1022','XXXXXXXXXXXXXXXX6367','Curabitur#dolortempus.org'),
('32','05/04/2010','4489509','Foster, Nasim','1463','XXXXXXXXXXXXXXXX7115','augue.eu.tellus#ullamcorperviverraMaecenas.ca'),
('95','01/02/2011','5384061','Browning, Owen','523','XXXXXXXXXXXXXXXX0576','sed.dictum.eleifend#accumsaninterdum.edu'),
('91','08/21/2010','6075234','Dawson, McKenzie','141','XXXXXXXXXXXXXXXX3580','dolor.sit.amet#etmagnis.org'),
('63','01/29/2010','1055619','Mathews, Keefe','1110','XXXXXXXXXXXXXXXX2682','ligula#Sednuncest.edu'),
('27','10/20/2010','1819662','Clarke, Briar','1474','XXXXXXXXXXXXXXXX7481','Donec.non.justo#malesuada.org'),
('82','03/05/2010','3184936','Holman, Dana','560','XXXXXXXXXXXXXXXX7080','Aenean.eget.magna#accumsan.edu'),
('24','06/11/2010','1007427','Kirk, Desiree','206','XXXXXXXXXXXXXXXX3681','parturient#at.com'),
('49','06/17/2010','6137066','Foley, Sopoline','1831','XXXXXXXXXXXXXXXX1718','ac.urna.Ut#pellentesqueafacilisis.org'),
('22','05/08/2010','3545367','Howell, Uriel','638','XXXXXXXXXXXXXXXX1945','ad.litora#arcuvelquam.ca'),
('5','10/25/2010','6836985','Little, Caryn','743','XXXXXXXXXXXXXXXX0821','Suspendisse.aliquet#auctor.org'),
('91','06/16/2010','6852582','Buckner, Chiquita','99','XXXXXXXXXXXXXXXX1533','tellus.sem#semvitaealiquam.edu'),
('63','06/12/2010','7930230','Nolan, Wyoming','1192','XXXXXXXXXXXXXXXX1291','Sed#diam.org'),
('32','02/01/2010','8407102','Cummings, Deacon','1315','XXXXXXXXXXXXXXXX4375','a.odio.semper#massaSuspendisseeleifend.ca'),
('75','06/29/2010','5502798','Guerrero, Unity','858','XXXXXXXXXXXXXXXX8000','eget#lectus.edu'),
('50','09/13/2010','8312525','Russo, Yvette','1680','XXXXXXXXXXXXXXXX2046','In.mi#eu.com'),
('11','04/13/2010','6204132','Small, Calista','426','XXXXXXXXXXXXXXXX0269','lacus#Cumsociisnatoque.org'),
('16','01/01/2011','7522507','Mosley, Thor','1459','XXXXXXXXXXXXXXXX8451','netus.et#Pellentesqueutipsum.com'),
('5','01/27/2010','1472120','Case, Kiona','1419','XXXXXXXXXXXXXXXX7097','Duis#duilectusrutrum.edu'),
('70','02/17/2010','1095935','Snyder, Tanner','1655','XXXXXXXXXXXXXXXX8556','metus.sit.amet#inconsequatenim.edu'),
('63','11/10/2010','3046441','Guerrero, Unity','629','XXXXXXXXXXXXXXXX0807','nonummy.ac.feugiat#Phasellusdapibus.org'),
('22','08/19/2010','5435100','Turner, Patrick','1133','XXXXXXXXXXXXXXXX6734','pede#Duis.edu'),
('96','10/05/2010','6381992','May, Dominic','1858','XXXXXXXXXXXXXXXX7227','hymenaeos#etcommodo.edu'),
('96','02/26/2010','8630748','Chandler, Olympia','1016','XXXXXXXXXXXXXXXX4001','sed.dui.Fusce#pellentesqueSed.com');
--insert a random fraud transaction to check against (based on customer and account_info only)
INSERT INTO [dbo].[test_userCheck] (confirmation_id, customer, total, account_info) VALUES
('2055015', 'Guerrero, Unity', '20.02', 'XXXXXXXXXXXXXXXX0821');
--get result, which is correct
SELECT a.confirmation_id, a.customer, a.total, a.account_info, a.email_address
FROM dbo.test_userData AS a RIGHT OUTER JOIN
dbo.test_userCheck AS b ON a.customer = b.customer OR a.account_info = b.account_info;
DROP TABLE [dbo].[test_userData];
DROP TABLE [dbo].[test_userCheck];
Create the appropriate index or indices. Just based on your question, I'd suggest two indices, one on test_userData.customer, and a second index on test_userData.account_info
Creating indexes would probably help, but have you considered another design that complies with normal forms. It would be better if you access the date through index on a integer column instead of string...