|
|
|
Old Hand
      
Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:38 AM
Points: 344,
Visits: 601
|
|
Hi all,
I'm wondering if there's a way to do the following:
IF OBJECT_ID('test') IS NOT NULL DROP TABLE test GO
CREATE TABLE test (nId INTEGER IDENTITY NOT NULL, nData INTEGER NOT NULL, nParent INTEGER NOT NULL) GO
ALTER TABLE test ADD CONSTRAINT PK_Test_nId PRIMARY KEY (nId) GO
ALTER TABLE test ADD CONSTRAINT DF_test_Parent DEFAULT SCOPE_IDENTITY() FOR nParent --DEFAULT @@IDENTITY FOR nParent GO
ALTER TABLE test ADD CONSTRAINT FK_test_Parent FOREIGN KEY (nParent) REFERENCES test (nId) GO
INSERT test (nData) SELECT 2 go
Either way, I get an error since SCOPE_IDENTITY() / @@IDENTITY are not set until the INSERT completes. Is there some way to make this scenario work only using DRI?
Thanks!
P
|
|
|
|
|
SSCrazy Eights
        
Group: General Forum Members
Last Login: 2 days ago @ 8:46 AM
Points: 8,547,
Visits: 8,204
|
|
|
|
|
|
Old Hand
      
Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:38 AM
Points: 344,
Visits: 601
|
|
I'm trying to set up a parent-child relationship. Some rows will be parents (nId = nParent), and some rows will be descendants (nId <> nParent).
In the past, I've always created the table with nParent NULL. To create a parent, I insert a row, and immediately update nParent to the newly created identity. (When creating a descendant, the nParent is always known.)
I was simply wondering if there was a way to create a parent in a single step.
|
|
|
|
|
SSCrazy Eights
        
Group: General Forum Members
Last Login: 2 days ago @ 8:46 AM
Points: 8,547,
Visits: 8,204
|
|
|
|
|
|
Old Hand
      
Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:38 AM
Points: 344,
Visits: 601
|
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Monday, May 06, 2013 1:09 PM
Points: 15,439,
Visits: 9,569
|
|
You can do what you're trying. Try this:
USE ProofOfConcept; GO CREATE TABLE dbo.SelfReferencing (ID INT IDENTITY PRIMARY KEY, ParentID INT NOT NULL DEFAULT (IDENT_CURRENT('dbo.SelfReferencing')) REFERENCES dbo.SelfReferencing (ID), RowName VARCHAR(50)); GO INSERT INTO dbo.SelfReferencing (ParentID, RowName) VALUES (DEFAULT, 'Row1: Parent'), (1, 'Row2: Child'); GO SELECT * FROM dbo.SelfReferencing; You can end up with problems with this one, if Ident_Current runs into a conflict between multiple concurrent inserts. So you'd need to pick a very strict locking scheme for every insert.
You can also use Scope_Identity in that. Like so:
USE ProofOfConcept; GO IF OBJECT_ID(N'dbo.SelfReferencing') IS NOT NULL DROP TABLE dbo.SelfReferencing; GO CREATE TABLE dbo.SelfReferencing (ID INT IDENTITY PRIMARY KEY, ParentID INT NOT NULL DEFAULT (SCOPE_IDENTITY()) REFERENCES dbo.SelfReferencing (ID), RowName VARCHAR(50)); GO INSERT INTO dbo.SelfReferencing (ParentID, RowName) VALUES (DEFAULT, 'Row1: Parent'), (1, 'Row2: Child'); GO SELECT * FROM dbo.SelfReferencing; If you test that, you'll find the problem with it immediately. Because the multi-row insert is treated as a single transaction (of course), the first row, which is supposed to be self-referent (a parent the way you do it), ends up being a child of the last row inserted. Not what you want.
The usual way to handle adjacency hierarchies (which is what this is), is to make parent rows have a NULL value in the ParentID column. Alternatively, if you don't want NULLs, you can put an arbitrary value in there, like 0 or -1. Since NULL technically means "unknown value" as well as "confirmed no value", that can represent the data better in some models. But NULL is usual, and works just fine in the vast majority of cases.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
Old Hand
      
Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:38 AM
Points: 344,
Visits: 601
|
|
In fact, neither works when inserting >1 parents.
I was simply wondering if I could save myself some code and a step with some fancy DRI. Now I see that while it can be made to work, it's probably more trouble than it's worth.
(And you can't just throw a 0 or -1 in there because of the FK.)
Thanks for having a look at this.
P
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Monday, May 06, 2013 1:09 PM
Points: 15,439,
Visits: 9,569
|
|
Since the usual model is NULL = top level, there isn't a built-in method to bypass that, so you're going to be stuck with custom code and solutions.
If you want to use the 0 or -1 version, you'd just have to create a row with that value, self-reference it, and then ignore it for all practical purposes. Would allow the FK to work. Wouldn't make querying any faster/easier, just would make inserting parent-rows easier, since they'd have a fixed value.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
Ten Centuries
      
Group: General Forum Members
Last Login: 2 days ago @ 2:38 PM
Points: 1,318,
Visits: 1,763
|
|
You could use an AFTER INSERT trigger to insure that the parent id got set to the identity column values ... but you still couldn't define the parent id as "NOT NULL", of course.
Even with an INSTEAD OF INSERT trigger, you run into timing issues on when the identity column value is assigned.
SQL DBA,SQL Server MVP('07, '08, '09) One man with courage makes a majority. Andrew Jackson
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Monday, May 06, 2013 1:09 PM
Points: 15,439,
Visits: 9,569
|
|
Yeah, the not null constraint is tricky.
If you really need it, try using GUIDs instead of an identity column. GUIDs (uniqueidentifier datatype) can be generated in the application, so you don't have to wait for the row to be populated in order to have the "ID" value.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|