Reason for using ##identity rather than scope_identity - sql-server

On a SQL Server 2005 database, one of our remote developers just checked in a change to a stored procedure that changed a "select scope_identity" to "select ##identity". Do you know of any reasons why you'd use ##identity over scope_identity?

##IDENTITY will return the last identity value issued by the current session. SCOPE_IDENTITY() returns the last identity value in the current session and same scope. They are usually the same, but assume a trigger is called which inserted something somewhere just before the current statement. ##IDENTITY will return the identity value by the INSERT statement of the trigger, not the insert statement of the block. It's usually a mistake unless he knows what he's doing.

Here is a link that may help differentiate them
looks like:
IDENTITY - last identity on the connection
SCOPE_IDENTITY - last identity you explicitly created (excludes triggers)
IDENT_CURRENT(’tablename’) - Last Identity in table regardless of scope or connection.

I can't think of any, unless there was a trigger then inserted a row (or somesuch) and I really really wanted the id of that trigger-inserted row rather than the row I physically changed.
In other words, no, not really.
DISCLAIMER: Not a T-SQL expert :)

Maybe you should ask the developer their rationale behind making the change.

If you wanted the trigger use you could get another trigger added on is the only reason I can come up with. Even then it's dangerous as another trigger could be added and again you would get the wrong identity. I suspect the developer doesn't know what he is doing. But honestly the best thing to do is to ask him why he made the change. You could change it back, but the developer needs to know not to do that again unless he needs the trigger identity as you may not catch it the next time.

Related

How to check the correctness of adding records to the transaction log?

I've got database ApressFinancial which i created from the book. (Robin Dewson - Beginning SQL Server for Developers (The Expert's Voice in SQL Server) - 2014)
I was asked a question: "How to check the correctness of adding records to the transaction log?" (And there was Hint that i can use trigger instead of)
Could not figure out.
Thank you.
I think you need a INSTEAD OF INSERT trigger in order to catch all your inserted data.
Basically, you create a trigger, which is a special type of stored procedure that lets you hook some functionality inside the transaction that should perform the INSERT (instead of will cause the insert intent to not fulfill). The trigger will expose a special table (not sure this is the exact term, but it behaves like one) called inserted that contains the information that is supposed to be inserted.
A more relevant example can be found here.
NOTE: also take a look upon AFTER INSERT trigger, as this type allows values to be inserted and provide a mechanism to use the values to perform other operations.

When does it make sense to use ##IDENTITY and not SCOPE_IDENTITY?

According to MSDN, ##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
Has anyone come across a situation where this functionality was useful? I can't think of a situation when you would want the last ID generated for any table across all scopes or how you would use it.
UPDATE:
Not sure what all the downvotes are about, but I figured I'd try to clarify what I'm asking.
First off I know when to use SCOPE_IDENTITY and IDENT_CURRENT. What I'm wondering is when would it be better to use ##IDENTITY as opposed to these other options? I have yet to find a place to use it in my day to day work and I'm wondering if someone can describe a situation when it is the best option.
Most of the time when I see it, it is because someone doesn't understand what they were doing, but I assume Microsoft included it for a reason.
In general, it shouldn't be used. SCOPE_IDENTITY() is far safer to use (as long as we're talking about single-row inserts, as highlighted in a comment above), except in the following scenario, where ##IDENTITY is one approach that can be used (SCOPE_IDENTITY() cannot in this case):
your code knowingly fires a trigger
the trigger inserts into a table with an identity column
the calling code needs the identity value generated inside the trigger
the calling code can guarantee that the ##IDENTITY value generated within the trigger will never be changed to reflect a different table (e.g. someone adds logging to the trigger after the insert you were relying on)
This is an odd use case, but feasible.
Keep in mind this won't work if you are inserting multiple rows and need multiple IDENTITY values back. There are other ways, but they also require the option to allow result sets from cursors, and IIRC this option is being deprecated.
##IDENTITY is fantastic for identifying individual rows based on an ID column.
ID | Name | Age
1 AA 20
2 AB 30
etc...
In this case the ID column would be reliant on the ##IDENTITY property.

How to create a column that can never be updated?

In SQL Server 2008, is it possible to create a column that can have a value inserted into it, but can never be updated? In other words, the column can have an initial value inserted into it, but once it contains a non-null value, it can never be changed. If possible, I would prefer to do it without using a trigger.
Thanks - Randy
You can't define a column as Read Only but can you not achieve your goal by setting permission against the column so it can be inserted but not updated by all the relevant users/roles/groups in your database?
Edit:
I misread a bit of your spec, if you need to allow someone to "insert" a null and it only goes read only when a null value is entered then you probably would need a trigger - either to block the updates or to set the deny permissions for the column after a non null value is entered.
You'll have to use a trigger.
You can GRANT INSERT and DENY UPDATE on the column itself, but that would stop you from being able to UPDATE from NULL to something after the initial INSERT.

How can I find out when a Sql Database field gets modified?

One of my database fields in a table is getting modified by some piece of code. I just can't figure out where!
So, I was wondering if there's a way I can find out.
I'm using SQL 2008. Can Profiler be used to find out if a particular field is getting updated? How?
What about a Trigger? If using a trigger (eg. on UPDATE) can you determine what code called it? How can the trigger 'notify me' of this? Email/file?
Yes, an "AFTER UPDATE" trigger on that particular table and field might give you some clues as to when and why the field gets changed.
From Books Online:
CREATE TRIGGER reminder
ON Person.Address
AFTER UPDATE
AS
IF ( UPDATE (StateProvinceID) OR UPDATE (PostalCode) )
BEGIN
RAISERROR (50009, 16, 10)
END;
GO
A trigger can execute basically any T-SQL code - if you have database mail set up correctly, it could send you an e-mail, yes. Or it can write an audit entry into another table or something like that.
EDIT: If you need to find out which statements updated your column, you might be actually better off running a trace on the server, limited to that specific table, and just trace what's happening there. I don't think a trigger can give you that information (which code caused the update to happen).
Marc
Determining the last Update to or Select against a table (without a trigger!)
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2007/06/03/determining-the-last-update-to-or-select-against-a-table-without-a-trigger.aspx
Yes, you can use a trigger to execute some code (keep track of who updated the table, email you, etc.) when a table is updated. See this link: Track Updates with a Database Trigger
edit: originally posted the wrong link

Cannot delete from the database...?

So, I have 2 database instances, one is for development in general, another was copied from development for unit tests.
Something changed in the development database that I can't figure out, and I don't know how to see what is different.
When I try to delete from a particular table, with for example:
delete from myschema.mytable where id = 555
I get the following normal response from the unit test DB indicating no row was deleted:
SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table. SQLSTATE=02000
However, the development database fails to delete at all with the following error:
DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command. During SQL processing it returned: SQL0440N No authorized routine named "=" of type "FUNCTION" having compatible arguments was found. SQLSTATE=42884
My best guess is there is some trigger or view that was added or changed that is causing the problem, but I have no idea how to go about finding the problem... has anyone had this problem or know how to figure out what the root of the problem is?
(note that this is a DB2 database)
Hmm, applying the great oracle to this question, I came up with:
http://bytes.com/forum/thread830774.html
It seems to suggest that another table has a foreign key pointing at the problematic one, when that FK on the other table is dropped, the delete should work again. (Presumably you can re-create the foreign key as well)
Does that help any?
You might have an open transaction on the dev db...that gets me sometimes on SQL Server
Is the type of id compatible with 555? Or has it been changed to a non-integer type?
Alternatively, does the 555 argument somehow go missing (e.g. if you are using JDBC and the prepared statement did not get its arguments set before executing the query)?
Can you add more to your question? That error sounds like the sql statement parser is very confused about your statement. Can you do a select on that table for the row where id = 555 ?
You could try running a RUNSTATS and REORG TABLE on that table, those are supposed to sort out wonky tables.
#castaway
A select with the same "where" condition works just fine, just not delete. Neither runstats nor reorg table have any affect on the problem.
#castaway
We actually just solved the problem, and indeed it is just what you said (a coworker found that exact same page too).
The solution was to drop foreign key constraints and re-add them.
Another post on the subject:
http://www.ibm.com/developerworks/forums/thread.jspa?threadID=208277&tstart=-1
Which indicates that the problem is a referential constraint corruption, and is actually, or supposedly anyways, fixed in a later version of db2 V9 (which we are not yet using).
Thanks for the help!
Please check
1. your arguments of triggers, procedure, functions and etc.
2. datatype of arguments.

Resources