I use this code in SQL Server 2012:
INSERT INTO [dbo].[test] ([t])
VALUES ('tyy');
SELECT [Id]
FROM [dbo].[test]
WHERE ([Id] = SCOPE_IDENTITY())
It returns the last inserted id and it worked well.
But the same code in vb.net 2017 and .net Framework 4.7.2 is not working - for every insert, it returns 1.
This is the code:
Dim id = TestTableAdapter.InsertQuery("nvnh")
Table:
CREATE TABLE [dbo].[test]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[t] NVARCHAR (50) NULL,
CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED ([Id] ASC)
);
thanks for all.
i finally found the solution.
i use already any from above solutions,
but the query eqcutemode is NonQuery ,so it give me the count of inserted rows
i changed it to Scalar
Related
I have something like this:
CREATE TABLE [dbo].[table1]
(
[id1] [int] IDENTITY(1,1) NOT NULL,
[data] [varchar](255) NOT NULL,
CONSTRAINT [PK_table1] PRIMARY KEY(id1)
)
CREATE TABLE [dbo].[table2]
(
[id2] [int] IDENTITY(1,1) NOT NULL,
[id1] [int] ,
CONSTRAINT [PK_table2] PRIMARY KEY (id2)
CONSTRAINT [FK_table2] FOREIGN KEY(id1) REFERENCES Table1
)
I want to add values to both the tables using a procedure. I'm not adding any key values just data values.
If I use INSERT INTO to add data into Table 1, its primary key will be autoincremented. I will also be incrementing the Table 2 in the same procedure.
I want that the autoincremented primary key of Table 1 should automatically be updated as foreign key in Table 2 when I run that procedure.
You need to do something like this:
CREATE PROCEDURE dbo.InsertData (#data VARCHAR(255))
AS
BEGIN
-- Insert row into table1
INSERT INTO dbo.Table1 (data) VALUES (#data);
-- Capture the newly generated "Id1" value
DECLARE #NewId1 INT;
SELECT #NewId1 = SCOPE_IDENTITY();
-- Insert data into table2
INSERT INTO dbo.table2 (Id1) VALUES (#NewId1);
END
I don't know if I understand what do you want to do but I think you can do something like this:
INSERT INTO table1 (data) VALUES 'mydata'
DECLARE #LastKey INT
SET #LastKey = SCOPE_IDENTITY() -- FOR SQL SERVER, OR LAST_INSERT_ID() FOR MYSQL
INSERT INTO table2 (data) VALUES #LastKey
How to have an identity column for a temp table in SQL?
Explicit value must be specified for identity column in table '#T'
either when IDENTITY_INSERT is set to ON or when a replication user is
inserting into a NOT FOR REPLICATION identity column.
I am getting SQL Syntax error for the below block.
if object_id('tempdb.dbo.#t') is not null
drop table #t
create table #t
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[TotalCount] int,
[PercentageComplete] nvarchar(4000)
)
insert into #t
select totalcount, percentagecomplete from table_a
Add this to your query after table declaration
SET IDENTITY_INSERT #t OFF
This should fix it. The following code works on my machine
CREATE TABLE #t
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[TotalCount] INT,
[PercentageComplete] NVARCHAR(4000)
)
SET IDENTITY_INSERT #t OFF
INSERT INTO #t
SELECT
totalcount, percentagecomplete
FROM
table_a
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])
Goal
I aim to create SSIS (ETL) Template that enables audit functionality (Audit Dimension). I've discovered a few ways to implement audit dimension that are described below with some reference links below:
SEQUENCE
Primary Key
Best way to get identity of inserted row?
Environment:
There are millions of rows in a fact tables and packages run a few
times a day.
Incremental ETL gets thousands of rows.
SQL Server 2012 BI edition is used for the BI solution.
Simplified Schema of DimAudit table:
CREATE TABLE [dw].[DimAudit] (
[AuditKey] [int] IDENTITY(1 ,1) NOT NULL,
[ParentAuditKey] [int] NOT NULL,
[TableName] [varchar] (50) NOT NULL DEFAULT ('Unknown'),
[PackageName] [varchar] (50) NOT NULL DEFAULT ('Unknown'),
[ExecStartDate] [datetime] NOT NULL DEFAULT ( getdate()),
[ExecStopDate] [datetime] NULL,
[SuccessfulProcessingInd] [char] (1) NOT NULL DEFAULT ('N'),
CONSTRAINT [PK_dbo.DimAudit] PRIMARY KEY CLUSTERED
(
[AuditKey] ASC
)
) ON [PRIMARY]
ALTER TABLE [dw].[DimAudit] WITH CHECK ADD CONSTRAINT [FK_DimAudit_ParentAuditKey] FOREIGN KEY( [ParentAuditKey])
REFERENCES [dw]. [DimAudit] ( [AuditKey])
GO
ALTER TABLE [dw].[DimAudit] CHECK CONSTRAINT [FK_DimAudit_ParentAuditKey]
GO
Primary Key Option:
Primary key is generated in the audit table and then AuditKey is queried.
Task: Master SQL Audit Generates Key (SQL Task)
INSERT INTO [dw].[DimAudit]
(ParentAuditKey
,[TableName]
,[PackageName]
,[ExecStartDate]
,[ExecStopDate]
,[SuccessfulProcessingInd])
VALUES
(1
,'Master Extract Package'
,?
,?
,?
,'N')
SELECT AuditKey
FROM [dw].[DimAudit]
WHERE TableName = 'Master Extract Package' and ExecStartDT = ?
/*
Last Parameter: ParameterSystem::StartTime
Result Set populates User::ParentAuditKey
*/
Task: Master SQL Audit End (SQL Task)
UPDATE [dw]. [DimAudit]
SET ParentAuditKey = AuditKey
,ExecStopDT = SYSDATETIME()
,SuccessfulProcessingInd= 'Y'
WHERE AuditKey = ?
/*
Parameter: User::ParentAuditKey
*/
SEQUENCE Option:
The sequence option does not select primary key (AuditKey) but uses logic below to create next available AuditKey.
CREATE SEQUENCE dbo . AuditID as INT
START WITH 1
INCREMENT BY 1 ;
GO
DECLARE #AuditID INTEGER ;
SET #AuditID = NEXT VALUE FOR dbo. AuditID ;
Best way to get identity of inserted row?
It feels risky using identity options as ETL packages could be executed in parallel.
Question
What is the recommended practice for audit dimension table and managing keys?
Sequence & primary key options do the job; however, I have concerns about the selecting primary key option because package could be executed the same millisecond (in theory) and therefore, a few primary keys would exist. So, Sequence sounds like the best option.
Is anything better I could do to create Audit Dimension for a data mart?
You could use the OUTPUT syntax:
INSERT INTO [dw].[DimAudit]
(ParentAuditKey
,[TableName]
,[PackageName]
,[ExecStartDate]
,[ExecStopDate]
,[SuccessfulProcessingInd])
OUTPUT inserted.AuditKey
VALUES
(1
,'Master Extract Package'
,?
,?
,?
,'N')
or SCOPE_IDENTITY() which is what I'm personally using:
INSERT INTO Meta.AuditDim (
Date,
UserName,
Source,
SourceType,
AuditType,
ExecutionId,
ExecutionHost,
ParentAuditKey,
FileID
)
VALUES (
GETDATE(),
CURRENT_USER,
#Source,
#SourceType,
#AuditType,
#ExecutionId,
#ExecutionHost,
#ParentAuditKey,
#FileID
);
SELECT AuditKey FROM Meta.AuditDim WHERE AuditKey = SCOPE_IDENTITY();
I have SQL Server Merge Replication setup on two servers and I am getting a key constraint error when the synchronization runs. The only way I can resolve this issue is to delete the record on one of the servers and then run synchronization.
Question: Is there a way to configure replication or a resolver so that the publisher record wins and the subscriber record is automatically removed when it encounters a unique or primary key violation?
Sample Table:
CREATE TABLE [dbo].[tblPeople](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[col1] [int] NULL,
[col2] [int] NULL,
[col3] [int] NULL,
[name] [varchar](52) NULL
CONSTRAINT [UK_keys] UNIQUE NONCLUSTERED
(
[col1] ASC,
[col2] ASC,
[col3] ASC
)
Insert on Server 1
INSERT into tblPeople (col1, col2, col3, name) values (1, 1, 1, 'Server 1 Insert')
Insert on Server 2
INSERT into tblPeople (col1, col2, col3, name) values (1, 1, 1, 'Server 2 Insert')
Trigger synchronization, which results in this conflict error and both servers having their own version of this record.
A row insert at 'SERVER1.TestDb' could not be propagated to 'SERVER2.TestDb'. This failure can be caused by a constraint violation. Violation of UNIQUE KEY constraint 'UK_keys'. Cannot insert duplicate key in object 'dbo.tblPeople'. The duplicate key value is (1, 1, 1).
Everything I read about this suggests adding a unique guid or using identity columns, which isn't a solution to this problem. The identity ranges work great and I can even create my own rowguid, but that still doesn't solve the constraint violation where I end up needing to manually delete the records.
This person asked a similar question, but I need the unique key on top of the guid and identity.
Automatically resolve primary key merge conflict
This was resolved by setting compensate_for_errors to true on the merge article. By default SQL Server doesn't trigger a resolver when a constraint error occurs. You cannot change this setting through the user interface and must use t-sql to update it.
exec sp_changemergearticle #publication = 'PublicationName'
, #article = 'TableName'
, #property = 'compensate_for_errors'
, #value = N'true'
, #force_invalidate_snapshot = true
, #force_reinit_subscription = true
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.replication.mergearticle.compensateforerrors.aspx