Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 123»»»

Quick Opinion on @@ROWCOUNT vs EXISTS Expand / Collapse
Author
Message
Posted Wednesday, January 11, 2012 9:32 AM


Ten Centuries

Ten CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen Centuries

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:16 AM
Points: 1,196, Visits: 1,319
Hi,
I'm editing a large stored procedure (very few comments) which has 3 methods (so far) of getting or creating an @ID variable - which is then used immediately.

I'd like your opinions on which construct you would favour, and why.

CREATE TABLE myTable (pKey INT IDENTITY(1,1) PRIMARY KEY,
CODE VARCHAR(10));
DECLARE @MYCODE VARCHAR(10);
SET @MYCODE = 'MYCODE';

DECLARE @ID INT;

--- Option 1 Using ROWCOUNT
SELECT @ID = pKey FROM myTable (NOLOCK) WHERE CODE=@MYCODE;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO myTable (CODE)
VALUES (@MYCODE);
SET @ID=@@IDENTITY;
END

-- Option 2
SELECT @ID = pKey FROM myTable WHERE CODE=@MYCODE;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO myTable (CODE)
VALUES (@MYCODE);
SELECT @ID=SCOPE_IDENTITY();
END

--- Option 3 Using EXISTS
IF NOT EXISTS (SELECT * FROM myTable WHERE CODE=@MYCODE)
BEGIN
INSERT INTO myTable (CODE)
VALUES (@MYCODE);
END
SELECT @ID=pKey FROM myTable WHERE CODE=@MYCODE;



Post #1234124
Posted Wednesday, January 11, 2012 9:35 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 10:27 AM
Points: 37,648, Visits: 29,900
In that case, 2 (though I might check if the variable is null or not rather than @@RowCount (which might be affected by triggers), and use Output instead of the scope_identity function)

Not 1 because of possible triggers affecting @@Identity
Not 3 because it has you selecting from the table twice (why)



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1234127
Posted Wednesday, January 11, 2012 9:36 AM
UDP Broadcaster

UDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP Broadcaster

Group: General Forum Members
Last Login: Tuesday, April 30, 2013 12:46 PM
Points: 1,493, Visits: 239
none of those :)

I would use the 3rd one (EXISTS) at the beginning and get the ID with SCOPE_IDENTITY at the end !



Post #1234128
Posted Wednesday, January 11, 2012 9:40 AM


SSChampion

SSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampion

Group: General Forum Members
Last Login: 2 days ago @ 12:22 PM
Points: 10,571, Visits: 11,871
How about option 4:

Declare @ids Table (id INT);

IF NOT EXISTS (SELECT * FROM myTable WHERE CODE=@MYCODE)
BEGIN
INSERT INTO myTable (CODE)
OUTPUT Inserted.id into @ids
VALUES (@MYCODE);

Select @id = id from @ids
END





Jack Corbett

Applications Developer

Don't let the good be the enemy of the best. -- Paul Fleming

Check out these links on how to get faster and more accurate answers:
Forum Etiquette: How to post data/code on a forum to get the best help
Need an Answer? Actually, No ... You Need a Question
How to Post Performance Problems
Crosstabs and Pivots or How to turn rows into columns Part 1
Crosstabs and Pivots or How to turn rows into columns Part 2
Post #1234134
Posted Wednesday, January 11, 2012 9:40 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 10:27 AM
Points: 37,648, Visits: 29,900
azdzn (1/11/2012)
none of those :)

I would use the 3rd one (EXISTS) at the beginning and get the ID with SCOPE_IDENTITY at the end !


In that case, how would you get the ID if it did exist (and hence didn't insert)?



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1234135
Posted Wednesday, January 11, 2012 9:41 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 10:27 AM
Points: 37,648, Visits: 29,900
Jack Corbett (1/11/2012)
How about option 4:

Declare @ids Table (id INT);

IF NOT EXISTS (SELECT * FROM myTable WHERE CODE=@MYCODE)
BEGIN
INSERT INTO myTable (CODE)
OUTPUT Inserted.id into @ids
VALUES (@MYCODE);

Select @id = id from @ids
END



Again, how does that get you the value for ID for that code if it's already in the table and doesn't need inserting?



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1234136
Posted Wednesday, January 11, 2012 9:46 AM
UDP Broadcaster

UDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP Broadcaster

Group: General Forum Members
Last Login: Tuesday, April 30, 2013 12:46 PM
Points: 1,493, Visits: 239
GilaMonster (1/11/2012)
azdzn (1/11/2012)
none of those :)

I would use the 3rd one (EXISTS) at the beginning and get the ID with SCOPE_IDENTITY at the end !


In that case, how would you get the ID if it did exist (and hence didn't insert)?



Yes you're right Gail. Option 2 then !



Post #1234142
Posted Wednesday, January 11, 2012 9:49 AM


SSChampion

SSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampion

Group: General Forum Members
Last Login: 2 days ago @ 12:22 PM
Points: 10,571, Visits: 11,871
GilaMonster (1/11/2012)
Jack Corbett (1/11/2012)
How about option 4:

Declare @ids Table (id INT);

IF NOT EXISTS (SELECT * FROM myTable WHERE CODE=@MYCODE)
BEGIN
INSERT INTO myTable (CODE)
OUTPUT Inserted.id into @ids
VALUES (@MYCODE);

Select @id = id from @ids
END



Again, how does that get you the value for ID for that code if it's already in the table and doesn't need inserting?


Oops, you are right, I missed that part. Yes I'd probably do option 2 then.




Jack Corbett

Applications Developer

Don't let the good be the enemy of the best. -- Paul Fleming

Check out these links on how to get faster and more accurate answers:
Forum Etiquette: How to post data/code on a forum to get the best help
Need an Answer? Actually, No ... You Need a Question
How to Post Performance Problems
Crosstabs and Pivots or How to turn rows into columns Part 1
Crosstabs and Pivots or How to turn rows into columns Part 2
Post #1234145
Posted Wednesday, January 11, 2012 9:58 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 10:27 AM
Points: 37,648, Visits: 29,900
P.S. I'll offer the anti-pattern that I've been cleaning out of some procedures recently (comments mine)

DECLARE @count int, @id int
SET @Count = (SELECT count(*) from myTable WHERE Code = @MyCode) -- count all rows to see if there are any... Isn't there another function for that?
IF @Count <= 0
BEGIN
Insert into myTable (Code)
Values (@MyCode)

SET @id = MAX(id) FROM MyTable -- race condition, what race condition???
END

SET @id = (SELECT id FROM MyTable WHERE Code = @MyCode) -- let's hope there's a unique constraint. Oh wait, no constraints.




Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1234159
Posted Wednesday, January 11, 2012 10:35 AM


SSChampion

SSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampion

Group: General Forum Members
Last Login: Wednesday, May 08, 2013 10:33 AM
Points: 10,989, Visits: 10,529
None of them for the reasons already stated, plus option 2 also contains a race condition.

DECLARE @MYCODE int = NULL
DECLARE @ID int = NULL
DECLARE @OUTPUT TABLE (ID int)

MERGE dbo.myTable WITH (HOLDLOCK) AS t
USING (VALUES(@MYCODE)) AS u (MyCode)
ON EXISTS (SELECT t.CODE INTERSECT SELECT u.MyCode)
WHEN NOT MATCHED THEN INSERT (CODE) VALUES (@MYCODE)
WHEN MATCHED THEN UPDATE SET @ID = t.pKey
OUTPUT INSERTED.pKey INTO @OUTPUT (ID);

SELECT
CASE
WHEN @ID IS NOT NULL THEN @ID
ELSE (SELECT TOP(1) ID FROM @OUTPUT)
END





Paul White
SQL Server MVP
SQLblog.com
@SQL_Kiwi
Post #1234186
« Prev Topic | Next Topic »

Add to briefcase 123»»»

Permissions Expand / Collapse