How to write multi-line constraint for ParentId/HierarchyId - sql

I have a table called Items with these three fields:
Id (int)
ParentId(int)
NodeId (HierarchyId)
Id NodeId ParentId
2 / NULL
3 /120/1/ 1520
4 /1/ 2
ParentId and NodeId are basically duplicates as they both point to the parent. In the future, ParentId will be dropped in favor of the HierarchyId.
However, in the meantime, I need to ensure that they stay in sync, so I need to write a constraint to ensure this:
declare #id int = 4
DECLARE #result int = 0, #parentNodeId1 HierarchyId,#parentNodeId2 HierarchyId, #parentId int;
Select #parentNodeId1 = NodeId.GetAncestor(1), #parentId = parentId from Items where id = #id;
Select #parentNodeId2 = NodeId from Items where Id = #parentId;
if #parentNodeId1 = #parentNodeId2
Select #result = 1;
How do I write this as a constraint?
Update
I tried Damiens solution as suggested. It works to enforce the multi-column integrity on existing data. However, the NodeId can change from left to right in the hierarchy. For example a NodeId of /1/ can change to /3/. It's parent has not changed (the parent is /), so really the Foreign Key has not been in-validated. And this works for items with no children.
However, if an item has children, and the NodeId is changed, the database engine sees it as a violation of the Foreign Key and throws an error.
See this DB Fiddle: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=44637c2bbed80b8db3f305933798cdad
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[People](
[Id] [int] NOT NULL,
[ParentId] [int] NULL,
[NodeId] [hierarchyid] NOT NULL,
[_ParentNodeId] AS ([NodeId].[GetAncestor]((1))) PERSISTED,
CONSTRAINT [PK_People] PRIMARY KEY CLUSTERED
(
[Id] ASC,
[NodeId] 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 [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (1, NULL, N'/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (2, 1, N'/2/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (3, 1, N'/3/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (4, 2, N'/2/1/')
GO
INSERT [dbo].[People] ([Id], [ParentId], [NodeId]) VALUES (5, 4, N'/2/1/1.1/')
GO
ALTER TABLE [dbo].[People] WITH CHECK ADD CONSTRAINT [FK_People_Parent] FOREIGN KEY([ParentId], [_ParentNodeId])
REFERENCES [dbo].[People] ([Id], [NodeId])
GO
ALTER TABLE [dbo].[People] CHECK CONSTRAINT [FK_People_Parent]
GO
Update People set NodeId = N'/2/1/2/' where Id = 5--Works
Update People set NodeId = N'/2/2/' where Id = 4 --Error

If we can add another column, a foreign key constraint can enforce this:
create table T(
Id int not null,
NodeId hierarchyid,
ParentId int,
_ParentNodeId as NodeId.GetAncestor(1) persisted,
constraint PK_T primary key (Id,NodeId),
constraint FK_T_Parent foreign key (ParentId,_ParentNodeId) references T (Id,NodeId)
)
(I'm using the PK as the FK target, but any unique constraint will do if, say, Id is the current PK and you want to keep that)
I've prefixed the new column name with _. That's my convention for "I'm adding this column for my purposes in enforcing integrity. I don't expect anybody else to ever even look in it".

Related

Incorrect syntax when working with a variable in IDENTITY

I'm trying to create a new table with a primary key value that is a continuation of a previous table.
My code is:
DECLARE #Table1_NextKey INT
SELECT #Table1_NextKey = MAX(id) + 1
FROM [Copy of Table1]
CREATE TABLE [dbo].Table1
(
[ID] [int] NOT NULL IDENTITY(#Table1_NextKey, 1)
CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
But I get this error:
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near '#Table1_NextKey'
Is there a way to get the Create Table to work with the variable?
You are going about this the wrong way.
What you are clearly trying to do, is copy a table and then you would like to continue the identity values.
In this case, do not declare the seed value differently in the CREATE TABLE, just manually set it afterwards:
CREATE TABLE [dbo].Table1
(
[ID] [int] NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
-- Do some copying code here
DECLARE #Table1_NextKey INT =
(
SELECT #Table1_NextKey = MAX(id) -- not + 1
FROM Table1
);
DBCC CHECKIDENT (Table1 RESEED, #Table1_NextKey) WITH NO_INFOMSGS;
You can only use literal values for identity, you'll need to dynamically construct your create statement, as follows
declare #sql nvarchar(max)=Concat(N'
CREATE TABLE [dbo].Table1(
[ID] [int] NOT NULL IDENTITY(', #Table1_NextKey, N', 1) CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL)
ON [PRIMARY]')
exec sp_executesql #sql
Don't know why SQL Server is so weird about this but with Stu's help, I got this to work:
DECLARE #Table1_NextKey INT,
#SQL_command varchar(4000)
select #Table1_NextKey=max(id)+1 from [Copy of Table1]
set #SQL_command=
'CREATE TABLE [dbo].Table1(
[ID] [int] NOT NULL IDENTITY(' + convert(varchar(5), #Table1_Nextkey) + ', 1) CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL)
ON [PRIMARY]
GO'

Issues in SYSTEM_VERSIONING OFF - Insert record failed in SQL Server

I'm having a System Versioned Temporal Table namely [dbo].[Contact], for development purpose I tried to seed some old dated data. The table contains GENERATED ALWAYS column.
This question is a Child question of my exiting question Seed data with old dates in Temporal Table - SQL Server
Original Table Schema:
CREATE TABLE [dbo].[Contact](
[ContactID] [uniqueidentifier] NOT NULL,
[ContactNumber] [nvarchar](50) NOT NULL,
[SysStartTime] [datetime2](0) GENERATED ALWAYS AS ROW START NOT NULL,
[SysEndTime] [datetime2](0) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_Contact] PRIMARY KEY NONCLUSTERED
(
[ContactID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [PRIMARY]
WITH
(
SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[ContactHistory] , DATA_CONSISTENCY_CHECK = ON )
)
I tried to switch it OFF the SYSTEM_VERSIONING, by using the following SQL Code
ALTER TABLE dbo.Contact SET (SYSTEM_VERSIONING = OFF);
Now the Table becomes like a normal table
Now I tried to Insert a record in [dbo].[Contact]
INSERT INTO dbo.Contact
(
ContactID,
ContactNumber,
SysStartTime,
SysEndTime
)
VALUES
(
NEWID(), -- ContactID - uniqueidentifier
N'1234567890', -- ContactNumber - nvarchar
'2014-09-13 00:00:00', -- SysStartTime - datetime2
'9999-12-31 23:59:59' -- SysEndTime - datetime2
)
But Still I'm getting the same Error
Msg 13536, Level 16, State 1, Line 20 Cannot insert an explicit value
into a GENERATED ALWAYS column in table 'DevDB.dbo.Contact'. Use
INSERT with a column list to exclude the GENERATED ALWAYS column, or
insert a DEFAULT into GENERATED ALWAYS column.

SELECT * INTO FAILS

I have following table structure :
CREATE TABLE [dbo].[UTS_USERCLIENT_MAPPING_USER_LIST]
(
[MAPPING_ID] [int] IDENTITY(1,1) NOT NULL,
[USER_ID] [varchar](50) NULL,
[USER_EMAIL_ID] [varchar](100) NULL,
[USER_CREATED_DATE] [datetime] NULL,
[USER_IS_ACTIVE] [bit] NULL,
CONSTRAINT [PK_UTS_USERCLIENT_MAPPING_USER_LIST]
PRIMARY KEY CLUSTERED ([MAPPING_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]
In stored procedure I have this code:
ALTER PROCEDURE [dbo].[PROC_UTS_USER_CLIENTMAPPING_LIST_SET]
(#RETURN_CODE INT OUTPUT,
#RETURN_MESSAGE NVARCHAR(512) OUTPUT,
#XML_USER_LIST xml)
AS
BEGIN TRY
SELECT
ROW_NUMBER() OVER(ORDER BY x.value('USERNAME[1]','nvarchar(50)')) AS MAPPING_ID,
x.value('USERNAME[1]', 'nvarchar(50)') as USER_ID,
x.value('EMAILID[1]', 'nvarchar(50)') as USER_EMAIL_ID,
x.value('CREATEDDATE[1]', 'datetime') as USER_CREATED_DATE,
x.value('ISACTIVE[1]', 'bit') as USER_IS_ACTIVE
INTO #tempXML
FROM #XML_USER_LIST.nodes('/DocumentElement/dtLstUsers') AS TEMPTABLE(x)
SELECT *
INTO UTS_USERCLIENT_MAPPING_USER_LIST
FROM #tempXML
END TRY
My problem is that above stored procedure is not inserting data into UTS_USERCLIENT_MAPPING_USER_LIST from #tempXML table.
I have ensured that #tempXML table contains values.
There are a few flaws in your query:
1 - you are trying to insert an IDENTITY value without setting IDENTITY_INSERT ON before inserting into your table, and then set it to OFF
SET IDENTITY_INSERT UTS_USERCLIENT_MAPPING_USER_LIST ON
2 - SELECT * INTO table will assume the table doesn't exist and will try to create it there, will fail -> need to use INSERT INTO SELECT
INSERT INTO UTS_USERCLIENT_MAPPING_USER_LIST (cols)
SELECT cols
FROM #temp
3 - you are calculating the MAPPING_ID with ROW_NUMBER function which will start from 1 to n (where n is number of nodes you have in xml)every time, but your table has a PRIMARY KEY on MAPPING_ID column which implies is UNIQUE so 2nd time you want to insert MAPPING_ID 1, it will fail.
4 - If you have a CATCH block which is empty, it will hide your errors
Now, the solution without really understanding your needs regarding MAPPING_ID column, is to change the insert statement there to:
INSERT INTO UTS_USERCLIENT_MAPPING_USER_LIST ([USER_ID], [USER_EMAIL_ID], [USER_CREATED_DATE], [USER_IS_ACTIVE])
SELECT [USER_ID], [USER_EMAIL_ID], [USER_CREATED_DATE], [USER_IS_ACTIVE]
FROM #tempXML
OR if you have a valid MAPPING_ID found from xml somehow:
SET IDENTITY_INSERT UTS_USERCLIENT_MAPPING_USER_LIST ON
INSERT INTO UTS_USERCLIENT_MAPPING_USER_LIST ([MAPPING_ID], [USER_ID], [USER_EMAIL_ID], [USER_CREATED_DATE], [USER_IS_ACTIVE])
SELECT [MAPPING_ID], [USER_ID], [USER_EMAIL_ID], [USER_CREATED_DATE], [USER_IS_ACTIVE]
FROM #tempXML
SET IDENTITY_INSERT UTS_USERCLIENT_MAPPING_USER_LIST OFF
As per my understanding you need to mentioned all the column name apart from Mapping_ID. see below code
INSERT INTO UTS_USERCLIENT_MAPPING_USER_LIST (
USER_ID,
USER_EMAIL_ID,
USER_CREATED_DATE,
USER_IS_ACTIVE)
select USER_ID,
USER_EMAIL_ID,
USER_CREATED_DATE,
USER_IS_ACTIVE
from #tempXML
Looks like you need to turn on IDENTITY_INSERT as Sparky has suggested.
Also a possible solution is that you aren't using IDENTITY column at all - in case it's not needed. (In case this table is getting the data only from this store procedure there is no need to use IDENTITY column):
CREATE TABLE [dbo].[UTS_USERCLIENT_MAPPING_USER_LIST](
[MAPPING_ID] [int] NOT NULL,
[USER_ID] [varchar](50) NULL,
[USER_EMAIL_ID] [varchar](100) NULL,
[USER_CREATED_DATE] [datetime] NULL,
[USER_IS_ACTIVE] [bit] NULL,
CONSTRAINT [PK_UTS_USERCLIENT_MAPPING_USER_LIST] PRIMARY KEY CLUSTERED
(
[MAPPING_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]
Real problem was,
SELECT * INTO always creates new table.
So I needed to drop the existing table before its creation.
When I :
DROP TABLE UTS_USERCLIENT_MAPPING_USER_LIST
SELECT *
INTO UTS_USERCLIENT_MAPPING_USER_LIST
FROM #tempXML
Then it worked.
Thank You.
Couldn't you just skip the temporary table altogether?
-- TRUNCATE TABLE HERE, IF NEED BE
INSERT INTO UTS_USERCLIENT_MAPPING_USER_LIST (<ColumnList>)
SELECT
ROW_NUMBER() OVER(ORDER BY x.value('USERNAME[1]','nvarchar(50)')) AS MAPPING_ID,
x.value('USERNAME[1]', 'nvarchar(50)') as USER_ID,
x.value('EMAILID[1]', 'nvarchar(50)') as USER_EMAIL_ID,
x.value('CREATEDDATE[1]', 'datetime') as USER_CREATED_DATE,
x.value('ISACTIVE[1]', 'bit') as USER_IS_ACTIVE
FROM #XML_USER_LIST.nodes('/DocumentElement/dtLstUsers') AS TEMPTABLE(x)

How to increment a primary key in an insert statement in SQL Server 2005

I need to write an insert statement into a table the columns looks like this
demandtypeid (PK, FK, int, not null)
characvalueid (PK, FK, int, not null)
percentage (int null)
lastuser (varchar(100), null)
lastedited (datetime, null)
Here is the INSERT statement. Notice the there is not values at the
value( , , 'Bob')
as I think that's where the auto-increment command should go
insert into tr_demandtypecharac(demandtypeID, characvalueid, lastuser)
values( , , 'Bob')
Please help with a simple little statement
I just want to know how to manually insert into this table
Here's my table structure:
CREATE TABLE [dbo].[tr_demandtypecharac](
[demandtypeid] [int] NOT NULL,
[characvalueid] [int] NOT NULL,
[percentage] [int] NULL,
[lastuser] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[lastedited] [datetime] NULL,
CONSTRAINT [PK_tr_dtc_pkey] PRIMARY KEY CLUSTERED
(
[demandtypeid] ASC,
[characvalueid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[tr_demandtypecharac] WITH CHECK
ADD CONSTRAINT [FK_tr_dtc_cvid]
FOREIGN KEY([characvalueid]) REFERENCES [dbo].[tr_characvalue] ([characvalueid])
ALTER TABLE [dbo].[tr_demandtypecharac] WITH CHECK
ADD CONSTRAINT [FK_tr_dtc_dtid]
FOREIGN KEY([demandtypeid]) REFERENCES [dbo].[tr_demandtype] ([demandtypeid])
If you want an int column that is unique and autoincrementing, use the IDENTITY keyword:
CREATE TABLE new_employees
(
id_num int IDENTITY(1,1),
fname varchar (20),
minit char(1),
lname varchar(30)
)
Then when you insert into the table, do not insert anything for that column -- it will autoincrement itself.
Given the CREATE TABLE statement you posted, without auto-increment (aka identity) columns, you would insert providing all columns and values, like this:
insert into tr_demandtypecharac(
demandtypeid, characvalueid,
percentage, lastuser, lastedited)
values(2, 3, 80, 'Bob', '01/01/2012')
If, however, you do make them auto-increment by changing the CREATE TABLE to:
CREATE TABLE [dbo].[tr_demandtypecharac](
[demandtypeid] [int] NOT NULL IDENTITY(1,1),
[characvalueid] [int] NOT NULL IDENTITY(1,1),
[percentage] [int] NULL,
[lastuser] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[lastedited] [datetime] NULL,
CONSTRAINT [PK_tr_dtc_pkey] PRIMARY KEY CLUSTERED
(
[demandtypeid] ASC,
[characvalueid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
)
Then you would insert providing all non-identity (non-autoincrement) columns like this:
insert into tr_demandtypecharac(
percentage, lastuser,
lastedited)
values(80, 'Bob', '01/01/2012')
However, it is not common to have more than one column as an identity (autoincrement) column, and generally, this column is the only PRIMARY KEY column.
If a column is an autoincement column (which is different than a primary key column) then you omit the column in your insert statement and it will be filled in.
INSERT INTO tr_demandtypecharac (lastuser) VALUES ('Bob')
I had a similar issue and needed to update a purchased database with a set of records. My solution was to find the highest key used so far, then use that as the base of my insert. The core of it was ROWNUMBER() OVER(ORDER BY PART_CODE).
The key is the "recnum" field in the inadjinf table. I determined that the highest current key was 675400 and updated my query to be:
insert into inadjinf (recnum, user_id, adj_type, adj_status, trans_date, part_code, lotqty, uom, cost_ctr, lot, location, to_cost_ctr, to_location, rec_status, to_part_grade, to_rec_status, remarks1, uom_conv)
select ROW_NUMBER() OVER(ORDER BY INVDET.PART_CODE) + 675400 as recnum, 'CHRSTR' as user_id, 'M' as adj_type, 'O' as adj_status, '2020-10-23' as trans_date, invdet.part_code, sum(lotqty) as lotqty, uom,
cost_ctr, lot, location, 'NS' as to_cost_ctr, '500A' as to_location, rec_status, 'Q' as to_part_grade, 'H' as to_rec_status, 'NS Scrap Request from MSobers 10/21/2020' as remarks1, '1' as uom_conv
from invdet
inner join partmstr on invdet.part_code = partmstr.part_code
where
invdet.part_code In
(
'86038',
'1271',
'VM-0021',
'CO-0107',
...
'FO-0391',
'FO-0376'
)
and lot not in (select lot from inadjinf where trans_date = '2020-10-23' and user_id = 'CHRSTR')
group by invdet.part_code, uom, cost_ctr, lot, location, rec_status
My output started with 675401 and went up from there. In the end, I updated the system's internal "next id field" table record.
You should not use int as primary keys... heres a article about it: http://techtrainedmonkey.com/2012/07/30/why-integers-are-lousy-primary-keys/
but if you do... set the field as identity and Sql Server will do it for you... check it out: http://msdn.microsoft.com/en-us/library/ms186775.aspx

INSERT conflicted with foreign key - SQL Server bug?

UPDATE: the issue does not happen when run against SQL Server 2008. So this is something strange (or wrong) with SQL Server 2000.
I try to do a simple insert on SQL Server 2000:
INSERT INTO UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM Addresses
and I get this:
INSERT statement conflicted with
COLUMN FOREIGN KEY constraint
'FK569ABB5045EE0940'. The conflict
occurred in database 'Orders', table
'Addresses', column 'Id'.
I'm well aware of what this means, but I can't understand why conflict happens - notice that I insert IDs from the Addresses table, so they DO exist! Why can't SQL Server find them on the foreign key end in the Addresses table? Should I do silly
SELECT * FROM Addresses
WHERE Id NOT IN (SELECT Id FROM Addresses)
or what?
Some more info: the IDs are GUIDs, data comes from the legacy DB (import). First I populate Addresses, then try to insert into UserAddresses. If I do SELECT TOP 100 ... it works... so it's a problem with some record but I can't understand why it happens.
CREATE TABLE [Addresses] (
[Id] [uniqueidentifier] NOT NULL ,
PRIMARY KEY CLUSTERED ([Id]) ON [PRIMARY] ,
) ON [PRIMARY]
CREATE TABLE [Users] (
[Id] [uniqueidentifier] NOT NULL ,
PRIMARY KEY CLUSTERED ([Id]) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [UserAddresses] (
[UserId] [uniqueidentifier] NOT NULL ,
[AddressId] [uniqueidentifier] NOT NULL ,
CONSTRAINT [FK569ABB5045EE0940] FOREIGN KEY
(
[AddressId]
) REFERENCES [Addresses] (
[Id]
),
CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY
(
[UserId]
) REFERENCES [Users] (
[Id]
)
) ON [PRIMARY]
ALTER TABLE Addresses ADD UserId UNIQUEIDENTIFIER
INSERT INTO Addresses (UserId, Id)
SELECT legacy_userid, legacy_single_useraddressid -- both are guids
FROM LegacyUsers INNER JOIN LegacyAddresses
UPDATE: I've just done this without errors (query batch completed):
DECLARE c CURSOR FOR SELECT UserId, Id FROM Addresses
OPEN c
DECLARE #uid UNIQUEIDENTIFIER, #aid UNIQUEIDENTIFIER
FETCH NEXT FROM c INTO #uid, #aid
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #aid
INSERT INTO UserAddresses (UserId, AddressId)
VALUES (#uid, #aid)
FETCH NEXT FROM c INTO #uid, #aid
END
CLOSE c
DEALLOCATE c
I wonder why INSERT fails while foreach cursor works...
UPDATE: oops, after cursor completed, INSERT works, too. But it never works standalone. Here's what I do:
Run the import script so that it populates Addresses table
Manually run INSERT - it fails
Manually run CURSOR - it works
DELETE FROM UserAddresses
Manually run INSERT - it works now
Is it a magic or I'm a complete idiot missing something?
UPDATE: If I do
ALTER TABLE UserAddresses DROP CONSTRAINT FK569ABB5045EE0940
INSERT INTO UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM Addresses
alter table UserAddresses
add constraint FK569ABB5045EE0940
foreign key (AddressId)
references Addresses
it also works. I think it's a bug in SQL Server 2000 despite the "never blame the compiler" rule.
Update - The "harry" Schema
gbn commented that this could be a schema issue. I updated my original code example and was able to get (almost*) the exact error.
(* Note that I'm running this on 2008 and the OP is running on 2000. SQL 2008 schema-qualifies the table in the error message.)
Updated Code - The "harry" Schema
SET NOCOUNT ON
GO
--<< ========================== DROPS ==========================
IF OBJECT_ID('tempdb..#UserGUIDs') IS NOT NULL
DROP TABLE #UserGUIDs
GO
IF OBJECT_ID('tempdb..#AddressGUIDs') IS NOT NULL
DROP TABLE #AddressGUIDs
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('UserAddresses'))
DROP TABLE [UserAddresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Users'))
DROP TABLE [Users]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('dbo.Addresses'))
DROP TABLE dbo.[Addresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('harry.Addresses'))
DROP TABLE harry.[Addresses]
GO
--<< ========================== TABLES ==========================
--<< Users
CREATE TABLE [Users] (
[Id] uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
[UserName] varchar(10) NOT NULL
) ON [PRIMARY]
GO
--<< Addresses
CREATE TABLE harry.[Addresses] (
[Id] uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
[Address1] varchar(20) NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE dbo.[Addresses] (
[Id] uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
[Address1] varchar(20) NOT NULL
) ON [PRIMARY]
GO
--<< UserAddresses
CREATE TABLE [UserAddresses] (
[UserId] uniqueidentifier NOT NULL,
[AddressId] uniqueidentifier NOT NULL,
CONSTRAINT [FK569ABB5045EE0940] FOREIGN KEY ([AddressId]) REFERENCES [Addresses] ([Id]),
CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY ([UserId]) REFERENCES [Users] ([Id])
) ON [PRIMARY]
GO
--<< ========================== DATA ==========================
--<< Populate Users
CREATE TABLE #UserGUIDs ([UserId] uniqueidentifier)
GO
INSERT INTO [Users] ([UserName]) VALUES ('UserName1')
INSERT INTO [Users] ([UserName]) VALUES ('UserName2')
INSERT INTO [Users] ([UserName]) VALUES ('UserName3')
INSERT INTO [Users] ([UserName]) VALUES ('UserName4')
GO
INSERT INTO #UserGUIDs ([UserId]) SELECT [Id] FROM [Users]
GO
--<< Populate Addresses
CREATE TABLE #AddressGUIDs ([AddressId] uniqueidentifier)
GO
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('1234 First Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('2345 Second Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('3456 Third Street')
INSERT INTO harry.[Addresses] ([Address1]) VALUES ('4567 Fourth Street')
GO
INSERT INTO #AddressGUIDs ([AddressId]) SELECT [Id] FROM harry.[Addresses]
GO
PRINT 'Users'
SELECT * FROM [Users]
PRINT 'Addresses'
SELECT * FROM harry.[Addresses]
GO
--<< ========================== TEST ==========================
--<< Populate UserAddresses
INSERT INTO UserAddresses (UserId, AddressId)
SELECT
u.Id, -- UserID
a.Id -- AddressID
FROM harry.Addresses AS a
CROSS JOIN Users AS u
GO
PRINT 'UserAddresses'
SELECT * FROM [UserAddresses]
GO
Result
Msg 547, Level 16, State 0, Line 4
The INSERT statement conflicted with the FOREIGN KEY constraint "FK569ABB5045EE0940". The conflict occurred in database "RGTest1", table "dbo.Addresses", column 'Id'.
Original Post
queen3, here is a complete working example of what I think you're attempting. I tried to make it SQL 2000-compatible, but I only have 2005 and 2008 available.
Please create a new database and run this script. If it does not duplicate what you're trying to do, please explain or just post modified code.
This script works as-is, but I'm sure there is something that is different from your application.
Rob
Code
SET NOCOUNT ON
GO
--<< ========================== DROPS ==========================
IF OBJECT_ID('tempdb..#UserGUIDs') IS NOT NULL
DROP TABLE #UserGUIDs
GO
IF OBJECT_ID('tempdb..#AddressGUIDs') IS NOT NULL
DROP TABLE #AddressGUIDs
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('UserAddresses'))
DROP TABLE [UserAddresses]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Users'))
DROP TABLE [Users]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE [id] = OBJECT_ID('Addresses'))
DROP TABLE [Addresses]
GO
--<< ========================== TABLES ==========================
--<< Users
CREATE TABLE [Users] (
[Id] uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
[UserName] varchar(10) NOT NULL
) ON [PRIMARY]
GO
--<< Addresses
CREATE TABLE [Addresses] (
[Id] uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY,
[Address1] varchar(20) NOT NULL
) ON [PRIMARY]
GO
--<< UserAddresses
CREATE TABLE [UserAddresses] (
[UserId] uniqueidentifier NOT NULL,
[AddressId] uniqueidentifier NOT NULL,
CONSTRAINT [FK569ABB5045EE0940] FOREIGN KEY ([AddressId]) REFERENCES [Addresses] ([Id]),
CONSTRAINT [UserAddressesToAddressFK] FOREIGN KEY ([UserId]) REFERENCES [Users] ([Id])
) ON [PRIMARY]
GO
--<< ========================== DATA ==========================
--<< Populate Users
CREATE TABLE #UserGUIDs ([UserId] uniqueidentifier)
GO
INSERT INTO [Users] ([UserName]) VALUES ('UserName1')
INSERT INTO [Users] ([UserName]) VALUES ('UserName2')
INSERT INTO [Users] ([UserName]) VALUES ('UserName3')
INSERT INTO [Users] ([UserName]) VALUES ('UserName4')
GO
INSERT INTO #UserGUIDs ([UserId]) SELECT [Id] FROM [Users]
GO
--<< Populate Addresses
CREATE TABLE #AddressGUIDs ([AddressId] uniqueidentifier)
GO
INSERT INTO [Addresses] ([Address1]) VALUES ('1234 First Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('2345 Second Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('3456 Third Street')
INSERT INTO [Addresses] ([Address1]) VALUES ('4567 Fourth Street')
GO
INSERT INTO #AddressGUIDs ([AddressId]) SELECT [Id] FROM [Addresses]
GO
PRINT 'Users'
SELECT * FROM [Users]
PRINT 'Addresses'
SELECT * FROM [Addresses]
GO
--<< ========================== TEST ==========================
--<< Populate UserAddresses
INSERT INTO UserAddresses (UserId, AddressId)
SELECT
u.Id, -- UserID
a.Id -- AddressID
FROM Addresses AS a
CROSS JOIN Users AS u
GO
PRINT 'UserAddresses'
SELECT * FROM [UserAddresses]
GO
Random thought...
What credentials are you using, what did ORM use, and what schema?
eg the tables and FKs are actually using "bob" schema
bob.Addresses
bob.Users
bob.UserAddresses
but because of pre-SQL 2005 user/schema stuff, you are in "harry" schema...
INSERT INTO UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM Addresses
-- is actually
INSERT INTO harry.UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM bob.Addresses
-- or
INSERT INTO bob.UserAddresses (UserId, AddressId)
SELECT UserId, Id
FROM harry.Addresses
More than once I've enjoyed the spectacle of testers and developers getting different results because of lack of qualifying schema...
Check the UserAddresses table. Maybe someone has defined a (BAD!) trigger on the table that does some Evil to the Addresses or UserAddresses table somehow.