In SQL syntax prompt tool SQL Prompt. Why should avoid using @@ IDENTITY function?

SQL Prompt is a useful tool prompt SQL syntax. SQL Prompt retrieval object name in the database, the syntax, and code segments automatically, to provide users with the appropriate code for selection. Set automatic script makes the code easier to read - especially useful if the developer is not familiar with the script. SQL Prompt installation needed to use, can significantly improve the coding efficiency. In addition, users can customize as necessary to make it work in the intended manner.

This article shows why SQL Prompt has a "best practice" rules (BP010) to check the usage of @@ IDENTITY function, and suggests some ways to use less error-prone to get the latest IDENTITY value used in the table.

@@ IDENTITY function returns the last IDENTITY value created in the same session. If there is a trigger on the table, or the table is a copy of the publication, the value may sometimes be wrong. BP010 code analysis rules SQL Prompt will warn you if it detects that it is used in SQL code.

BP010.png

In contrast, SCOPE_IDENTITY () function returns the last identity IDENTITY created in the same range, so as a direct substitute safer. When the insert multiple rows, redesigning code, to obtain IDENTITY INSERT ... OUTPUT value and the calculated column. If the need to obtain the current value of the table IDENTITY use IDENT_CURRENT ( ' <TableName>').

@@ IDENTITY problem

IDENTITY columns generally added to the table to ensure that the only references to the table for each row. A table can have only one of these columns. It saves you create a natural combination of columns or columns from, the only trouble bond.

IDENTITY column using the "seed" the statement, the first value is inserted into the column, "increment" is supposed to add value to create value on a next value. You may be used IDENT_SEED ((<tablename>) to reference function, and the increment value can be referenced by IDENT_INCR (<tablename>) function.

In row is added to keep the original table object from the seed and increment values ​​of "identity" values, and use them to ensure that the rows are inserted to provide the correct values ​​for the row. Use each number only once. You may then be used to enforce the uniqueness constraint or a unique index by a unique on this column.

You might think that when you insert a table with an IDENTITY column, it is easy to find IDENTITY values ​​used, but not always, and you also can not assume that a complete sequence. Although the value inserted into the IDENTITY value of the order will be specified in increments, but that does not necessarily mean that your next INSERT statement will be assigned to a value in the sequence, because it may be assigned to different sessions INSERT in execution. SQL Server is a multi-user system, so other users may use the system by executing, even tries to insert, destroy sequence to "steal" some of the values ​​you expect. You can have a gap, not a complete sequence. If you want to specify the meaning of that sequence, this may be a problem.

@@ IDENTITY contains the last session IDENTITY value generated in the previous statement currently. If the data to be imported must be placed in a plurality of tables, and the other table contains the foreign key reference identifier field, this value is required. If not trigger or copy, you may be sure that this is the IDENTITY value that you just inserted row. However, if the statement is triggered to perform insert one or more triggers, which in turn triggers generated IDENTITY value, the risk exists does not happen, because you no longer know exactly what is in front of the INSERT statement Yes.

Let us show that as much as possible. We assume that you are creating a 10,000 Irish saints database contains (in medieval Ireland, have greatly reduced over a period of time required for the Saints identity). Saints in the table, we try to record their names and meanings, as well as saints date list of each person. Whenever we insert a new Saint, specific dates of each flip-flop is inserted in the saint SaintsDay table, the table is also used IDENTITY column as its primary key and the foreign key having Saint reference. The third table, YearOfSainthood record year created Every saint, and once again the IDENTITY column as the primary key and foreign key for Saints references.

/* drop our objects if they already exist */
 IF Object_Id('dbo.YearOfSainthood') IS not NULL 
   DROP TABLE dbo.YearOfSainthood
 IF Object_Id('dbo.saintsDay') IS not NULL 
   DROP TABLE dbo.saintsDay
 IF Object_Id('dbo.saints') IS not NULL 
   DROP TABLE dbo.Saints
 go
/* create a new name/meaning table for our Irish Saints */
 CREATE TABLE dbo.Saints
  (
  Saint_id INT IDENTITY(1, 1) PRIMARY KEY,
  name VARCHAR(20) NOT NULL,
  meaning VARCHAR(80) NOT NULL,
  SaintsDayList VARCHAR(4000) null
  );
/* and create a new Date table for the saints days
associated with the saint name */
CREATE TABLE dbo.SaintsDay
  (
  SaintsDay_id INT IDENTITY PRIMARY KEY,
  Saint_ID INT NOT NULL FOREIGN KEY REFERENCES dbo.Saints(Saint_id),
  DayAsString VARCHAR(500) NOT NULL,
  TheMonth INT NULL,
  TheDay INT NULL
  );
  GO
 CREATE TABLE dbo.YearOfSainthood
  (
  SainthoodYear_id INT IDENTITY PRIMARY KEY,
  Saint_ID INT NOT NULL FOREIGN KEY REFERENCES dbo.Saints(Saint_id),
  [Year] int
  );
  go 
  /* create a trigger that takes the list of saints' days and
  inserts them into a relational table */
CREATE TRIGGER GrabTheSaintsDays
    ON dbo.saints
    FOR INSERT
    AS
    BEGIN
    SET NOCOUNT ON
      INSERT INTO dbo.SaintsDay(Saint_id, DayAsString)
      SELECT saint_id, LTrim(value)
      FROM inserted
      OUTER APPLY STRING_SPLIT ( inserted.[SaintsDayList] , ',' ) 
    END
GO
-- Now INSERT a set of values into the saints table
INSERT INTO saints([name], meaning,saintsDayList)
SELECT [Name], Meaning,[Saints days]  FROM (VALUES
('Cruimín','crooked; bent','28 Jun'),
('Díocuill','?','17 Nov, 1 May, 28 Feb'),
('Fursa','?','16 Jun'),
('Faolchú','wolf; wolf-hound','23 May'),
('Líthghein','born with luck & prosperity','16 Jan'),
('Díomán','pet form of Diarmaid','10 Jan'),
('Onchú','fierce hound','9 Jul'),
(Fionbharr ',' fair-haired ', 4 Aug, 25 Aug, 9 Sep, 10 Sep, 25 Sep), 
(Darearca', daughter of Erc, 15 Jan, 9 Sep), 
( 'Enan,'? ', 29 Apr, 30 Jan'), 
( 'shoes', '?', 1 Jan, 9 Apr, 27 Jun, 8 Jul, 25 Aug, 21 Sep), 
(Faoiltiarn 'Lord of Wolves', 17'), 
( 'Daghán', 'good', 12, 13 Sep), 
(Laoire ', calf-Herd', 11 May), 
( 'Beoc', '?', 16 Dec), 
(Séanait 'hawk', 18 Dec), 
(meaning 'high; Noble', 31 Jan), 
(Dúinseach ' 'fortress?', 12 Dec, Aug 5), 
( 'Tuaimmíne ',' accents of Tómmán ',' 12 Jun, 10 Jan '), 
(' Fenian ',' wine-birth ',' 5 Feb '), 
(' Lonán '' blackbird ',' 6 Jun, 22 Jan , 7 Feb, 11 Jul, 2 Aug, 24 Sep, 1 Nov, 12 Nov '), 
(' Trout ',' freckled '' Jan 15 '), 
(' Scoithín ',' bloom; blossom ',' 2 Jan '),
(Teimhnín ',' dark ', 7 Aug, 17 Aug), 
(Aoidhghean, "born of Red", 1 May'), 
( 'cellular', lively-headed? '' 1 Apr, 7 Apr, 18 Jul, 7 Oct), 
( 'Fiachra', 'Battle-king?', 8 Feb, 2 May, 25 Jul, 30 Aug, 28 Sep), 
(Iobhar ' Vine ', 23 Apr), 
(Conna' Pet form of Colman ( 'Dove' '), Feb 3) 
) f ([Name], Meaning, [Saints days])

I do not know there is a trigger, and now naively tried to insert the details of his saints and saints of the Year:

12345    INSERT INTO saints([name], meaning,saintsDayList) 
VALUES ('Siadhal','','12 Feb, 8 Mar') 

 INSERT INTO YearOfSainthood (Saint_id, [Year])
VALUES (@@Identity,'759')

Sainthood的那一年会引用错误的圣人,或者没有圣人,但是因为我们有一个外键约束,它会导致外键约束违规:

Msg 547, Level 16, State 0, Line 89
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__YearOfSai__Saint__3F3159AB". The conflict occurred in database "master", table "dbo.Saints", column 'Saint_id'.

遗憾的是,@@IDENTITY不限于特定范围,即当前正在执行的模块(存储过程、触发器、函数或批处理),触发器将在同一会话中执行但范围不同。如果触发器插入到具有IDENTITY列的另一个表中,则@@IDENTITY将返回后续插入的标识值。同样,如果您的数据库是复制文章的一部分,那么该@@IDENTITY值将不可靠,因为它是在复制触发器和存储过程中使用的。

在我们的示例中,很容易证明@@IDENTITY现在显示SaintsDay表的IDENTITY字段而不是Saints表:

SELECT @@Identity AS [Value of @@Identity],
  Scope_Identity() AS [Value of scope_Identity],
  Max(Saint_id) AS [Largest ID Assigned],
  Ident_Current('dbo.saints') AS [Identity value of 'saints'],
  Ident_Current('dbo.saintsDay') AS [Identity value of 'saintsDay']
  FROM Saints;

word-image-35.png

为了避免这一切,只需获取最后一次插入的IDENTITY值,然后应该使用SCOPE_IDENTITY()函数语法。

虽然@@IDENTITY和SCOPE_ IDENTITY都为您提供了该会话中前一个语句中指定的最后一个IDENTITY字段的值(忽略范围或范围内),但您可能决定需要知道特定表的IDENTITY值。如果你这样做,那么IDENT_ CURRENT()函数会给出这个。您只需将表名指定为varchar即可。

带有IDENTITY的输出子句的Insert子句

尽管对@@IDENTITY函数的大多数用途的简单建议是用SCOPE_ IDENTITY替换它,但必须要说的是,在您希望确定导致插入多行的INSERT语句的IDENTITY值的情况下,使用OUTPUT子句提供了一种安全的方法,可以为每个插入的查找IDENTITY值,以及任何计算列,以防您需要它们。这是一个简单的例子来说明这一点。

CREATE TABLE #IrishSaintsDays
  (
  Saint_id INT IDENTITY,
  name NVARCHAR(50) NOT NULL,
  CurrentsaintsDate DATETIME2(7) NULL,
  SaintsDay AS Convert(VARCHAR(6), CurrentsaintsDate, 113)
  );
INSERT INTO #IrishSaintsDays (name, CurrentsaintsDate)
OUTPUT inserted.Saint_id, inserted.name, Inserted.SaintsDay
VALUES
  (N'Finten, also Fintan, Munnu', '2019-10-21T00:00:00'),
  (N'Énda mac Conaill', '2019-03-21T00:00:00'),
  (N'Olcán', '2019-02-20T00:00:00'),
  (N'Suibne moccu Urthrí', NULL),
  (N'Coirpre Crom mac Feradaig', '2019-03-06T00:00:00'),
  (N'Béoáed mac Ocláin', '2019-03-07T00:00:00'),
  (N'Cairech Dergain', '2019-02-09T00:00:00'),
  (N'Gobban Find mac Lugdach', NULL),
  (N'Fáelán Amlabar, Fillan', '2019-06-20T00:00:00'),
  (N'Commán mac Fáelchon, Mo Chommóc', '2019-12-26T00:00:00'),
  (N'Boethian of Pierrepoint', NULL),
  (N'Caomhán (Cavan, Kevin)', '2019-06-14T00:00:00'),
  (N'Manchán of Mohill (Manchán of Maothail)', '2019-02-25T00:00:00'),
  (N'Columba', NULL),
  (N'Raoiriú', NULL),
  (N'Dublitter', '2019-05-15T00:00:00'),
  (N'Cuimín of Kilcummin', NULL),
  (N'Fínán Cam mac Móenaig', '2019-04-07T00:00:00'),
  (N'Maonacan of Athleague', '2019-02-18T00:00:00'),
  (N'Scuithin', '2019-01-02T00:00:00');

word-image-36.png

If this output is inserted into the table variable, there are many opportunities to use information IDENTITY column to use to fill the IDENTITY field has a foreign key table for you to insert a reference to the associated table.

In this case, for example, I might want to watch associated with this table to provide the meaning of each part of the name, so that I can analyze all the saints of God's name from the Celtic name (for example Lugh, Hus , Brij or Finn), or may be related to the major sites of the saints, it represents tribal ancestors, or to provide good Christians to be the date of the saints.

in conclusion

We now offer a better way to deal with the popular use of the IDENTITY column to provide a primary key, providing a simple, unique reference line. In most cases, @@ IDENTITY function can be, but it has a range of problems that may make you feel confused. In the heat of the moment, it is easy to forget you insert a table with a trigger associated with it. SCOPE_IDENTITY best develop the use of alternative or customary usage more powerful, more versatile OUTPUT clause, these provisions did not even think early in the initial design of @@ IDENTITY.


Guess you like

Origin blog.51cto.com/14467432/2429221