2008-10-09 16 views
13

Tôi cần một hàm thực thi câu lệnh INSERT trên cơ sở dữ liệu và trả về khóa chính Auto_Increment. Tôi có mã C# sau nhưng, trong khi câu lệnh INSERT hoạt động tốt (tôi có thể xem bản ghi trong cơ sở dữ liệu, PK được tạo đúng và hàng == 1), giá trị id luôn là 0. Bất kỳ ý tưởng nào về những gì có thể xảy ra sai rồi?@@ IDENTITY sau câu lệnh INSERT luôn trả về 0

public int ExecuteInsertStatement(string statement) 
    { 
     InitializeAndOpenConnection(); 
     int id = -1; 


     IDbCommand cmdInsert = connection.CreateCommand(); 
     cmdInsert.CommandText = statement; 
     int rows = cmdInsert.ExecuteNonQuery(); 

     if (rows == 1) 
     { 
      IDbCommand cmdId = connection.CreateCommand(); 
      cmdId.CommandText = "SELECT @@Identity;"; 
      id = (int)cmdId.ExecuteScalar(); 
     } 

     return id; 
    } 
    private void InitializeAndOpenConnection() 
    { 
     if (connection == null) 
      connection = OleDbProviderFactory.Instance.CreateConnection(connectString); 

     if(connection.State != ConnectionState.Open)     
      connection.Open(); 
    } 

Đáp lại câu trả lời, tôi đã cố gắng:

public int ExecuteInsertStatement(string statement, string tableName) 
    { 
     InitializeAndOpenConnection(); 
     int id = -1; 
     IDbCommand cmdInsert = connection.CreateCommand(); 
     cmdInsert.CommandText = statement + ";SELECT OID FROM " + tableName + " WHERE OID = SCOPE_IDENTITY();"; 
     id = (int)cmdInsert.ExecuteScalar(); 

     return id; 
    } 

nhưng tôi là bây giờ nhận được lỗi "Nhân vật tìm thấy sau khi kết thúc câu lệnh SQL"

Tôi đang sử dụng MS Access cơ sở dữ liệu với kết nối OleDb, Nhà cung cấp = Microsoft.Jet.OLEDB.4.0

+0

Ông có thể làm rõ những gì máy chủ cơ sở dữ liệu bạn đang sử dụng và có thể là nội tuyến các tài liệu tham khảo để InitializeAndOpenConnection/connection.CreateCommand vì chúng có thể ảnh hưởng đến câu trả lời của chúng tôi để bạn? :) – Rob

+0

Ngoài ra - toàn bộ "SELECT OID FROM x nơi OID = SCOPE_IDENTITY()" thins là hơi phức tạp như bạn đang nói (đối với một bản ghi được chèn với một giá trị nhận dạng của 3): "SELECT 3 FROM table_x WHERE 3 = 3 "- kinda dự phòng – Rob

+0

@Rob: có vẻ như thừa, nhưng OID được nhập int, trong đó scope_identity() không phải, vì vậy bạn có thể trực tiếp truyền (int) cmd.ExecuteScalar() – devio

Trả lời

1

Tôi nghĩ rằng bạn cần phải có danh tính Select @@ với lệnh tạo đầu tiên - thử nối nó qua "; SELECT @@ Identity" và .ExecuteScalar chèn tuyên bố

0

Có bất kỳ trình kích hoạt nào trên bảng của bạn có thể được chèn vào các bảng khác không? Nói chung, chúng tôi khuyên bạn không nên sử dụng @@ Identity để ủng hộ IDENT_CURRENT để bạn có thể đảm bảo rằng danh tính được trả về dành cho bảng bạn vừa chèn vào.

+1

Tôi nghĩ bạn nên sử dụng SCOPE_IDENTITY vì nó trả về giá trị nhận dạng cuối cùng được tạo cho bất kỳ bảng nào trong phiên hiện tại và phạm vi hiện tại vì vậy nếu nó được gọi ngay sau bảng chèn vào bạn, bạn được đảm bảo nhận giá trị thích hợp. – kristof

+0

Với IDENT_CURRENT mặc dù bạn chỉ định tên bảng mà bạn không đảm bảo rằng nó nằm trong phạm vi hoạt động của bạn, hãy xem định nghĩa: "Trả về giá trị nhận dạng cuối cùng được tạo cho bảng hoặc chế độ xem được chỉ định. và bất kỳ phạm vi nào " – kristof

+0

Tôi nghĩ rằng hoặc có nhược điểm của nó sau đó. Cơ hội nhận được danh tính "khác" từ cùng một bảng sẽ tương tự như việc nhận dạng danh tính từ một bảng khác trong cùng phạm vi. Hoặc là tốt hơn so với @@ Identity. –

0

Tôi nghĩ rằng @@ identity chỉ hợp lệ trong phạm vi lệnh - trong trường hợp của bạn khi bạn thực hiện "câu lệnh".

Sửa đổi "câu lệnh" của bạn để chính thủ tục lưu sẵn sẽ trả về giá trị @@ IDENTITY ngay sau câu lệnh INSERT và đọc nó như là mã trả về của quá trình thực thi thủ tục đã lưu.

15

1) kết hợp INSERT và câu lệnh SELECT (concatenate sử dụng ";") vào lệnh 1 db

2) sử dụng SCOPE_IDENTITY() thay vì @@ IDENTITY

INSERT INTO blabla ...; CHỌN OID FROM table WHERE OID = SCOPE_IDENTITY()

- Cập nhật:

như nó bật ra rằng vấn đề có liên quan đến MS ACCESS, tôi thấy this article đó cho thấy rằng chỉ đơn giản là tái sử dụng lệnh đầu tiên và thiết lập CommandText của nó để "SELECT @@ IDENTITY" phải đủ.

+0

Lý do tại sao là bởi vì nếu không bạn đang phát hành hai lệnh, và lệnh thứ hai biết zilch về lệnh đầu tiên và vì vậy trong khi bạn đã tạo ra một giá trị IDENTITY bạn không nhận được nó từ lệnh thứ hai (ngắt kết nối). –

+0

Điều này cho tôi lỗi "Các ký tự được tìm thấy sau khi kết thúc câu lệnh SQL" – Gillian

+0

chỉ sử dụng "SELECT SCOPE_IDENTITY()" sau câu lệnh đầu tiên. xem liên kết của tôi dưới đây để có một giải thích tốt về điều này. – evilhomer

-1

Khi bạn đang sử dụng Access, hãy xem this article từ aspfaq, cuộn xuống khoảng một nửa xuống dưới trang. Các mã trong ASP cổ điển, nhưng hy vọng các nguyên tắc vẫn nên đứng.


SELECT @@ Danh tính kết thúc được coi là ngữ cảnh thực thi riêng biệt, tôi tin. Mã mà nên công việc sẽ là:

public int ExecuteInsertStatement(string statement) 
{ 
    InitializeAndOpenConnection(); 

    IDbCommand cmdInsert = connection.CreateCommand(); 
    cmdInsert.CommandText = statement + "; SELECT @@Identity"; 
    object result = cmdInsert.ExecuteScalar(); 

    if (object == DBNull.Value) 
    { 
     return -1; 
    } 
    else 
    { 
     return Convert.ToInt32(result); 
    } 
} 

Có thể bạn muốn/cần phải dọn dẹp các nối mà thêm 'SELECT @@ nhận dạng' vào cuối của mã mặc dù.

4

bạn cần phải trả lại danh tính cùng lúc khi bạn mở kết nối ban đầu. Trả lại tập hợp kết quả từ biến chèn hoặc biến đầu ra của bạn.

Bạn cũng nên luôn sử dụng SCOPE_IDENTITY() không phải @@ identity.Reference here

Bạn nên thêm

SELECT SCOPE_IDENTITY() 

Sau khi chèn.

+2

-1 Không phải trong cơ sở dữ liệu Access. – Fionnuala

0

Kiểm tra cài đặt cơ sở dữ liệu của bạn. Tôi đã có một vấn đề tương tự một thời gian trước đây và phát hiện ra rằng các thiết lập kết nối SQL Server 'no count' đã được kích hoạt.

Trong SQL Server Management Studio, bạn có thể tìm thấy điều này bằng cách bấm chuột phải vào máy chủ trong Object Explorer, chọn Thuộc tính và sau đó điều hướng đến trang Kết nối. Nhìn vào cài đặt cho "Tùy chọn kết nối mặc định"

+0

Doh, chỉ cần đọc rằng bạn đang sử dụng MS Access chứ không phải SQL Server. Không chắc chắn nếu câu trả lời của tôi áp dụng cho MS Access ... –

+0

Không sử dụng Access, nhưng Jet. –

4

Bạn đang sử dụng Jet (không phải SQL Server) và Jet chỉ có thể xử lý một câu lệnh SQL trên mỗi lệnh, do đó bạn cần thực thi SELECT @@IDENTITY trong một lệnh riêng biệt. cùng một kết nối với số INSERT.

0

Không phải hầu hết người trả lời đều quên rằng người hỏi không sử dụng SQL Server?

Dường như, MS Access 2000 và sau đó doesn't support @@IDENTITY. Cách khác là "Sử dụng sự kiện RowUpdated, bạn có thể xác định xem INSERT có xảy ra hay không, truy xuất giá trị @@ IDENTITY mới nhất và đặt nó vào cột nhận dạng của bảng cục bộ trong Tập dữ liệu".

Và có, đây là cho VBA được nhúng trong DB truy cập. Điều đó vẫn có thể gọi bên ngoài Access thông qua Thư viện đối tượng truy cập.

Chỉnh sửa: ok, được hỗ trợ, xin lỗi vì câu trả lời sáng sớm. Nhưng phần còn lại của câu trả lời này có thể hữu ích.

+0

"MS Access 2000 và sau đó không hỗ trợ @@ IDENTITY" - bạn đã có một cách sai lầm. @@ IDENTITY chỉ được hỗ trợ từ MS Access 2000 trở đi. OP cho biết họ đang sử dụng máy bay phản lực 4.0, lần đầu tiên được vận chuyển với MS Access 2000. – onedaywhen

+0

Hầu hết người trả lời không quên điều đó - thực tế là cơ sở dữ liệu đích được Access không được công bố cho đến sau một vài câu trả lời hợp lý đã được thực hiện :) – Rob

+0

Đạo đức của câu chuyện: không trả lời câu hỏi lúc 6 giờ sáng – moffdub

7

Nhà cung cấp Microsoft.Jet.OLEDB.4.0 hỗ trợ cơ sở dữ liệu Jet v3 và Jet v4, tuy nhiên SELECT @@ IDENTITY không được hỗ trợ cho Jet v3.

MSAccess 97 là Máy bay phản lực v3 và không hỗ trợ SELECT @@ IDENTITY; Nó hỗ trợ trên MSAccess 2000 trở lên.

+0

Sau khi có cùng một vấn đề tôi đã đi đến cùng một kết luận. Tất cả "giải pháp" khác trong các câu trả lời khác chỉ đơn giản là không áp dụng cho Access/Jet. –

0

Nếu bạn muốn truy xuất giá trị của số lượng giao dịch tự động đang chạy mà bạn đang chèn và môi trường của bạn theo sau 1. Cơ sở dữ liệu là MsAccess. 2. Trình điều khiển là Jet4 với chuỗi kết nối như thế này "Nhà cung cấp = Microsoft.Jet.OLEDB.4.0; Mật khẩu = {0}; Nguồn dữ liệu = {1}; Thông tin bảo mật liên tục = True" 3. sử dụng Oledb

bạn có thể áp dụng ví dụ của tôi để mã của bạn

OleDbConnection connection = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True",dbinfo.Password,dbinfo.MsAccessDBFile); 
connection.Open(); 
OleDbTransaction transaction = null; 
try{ 
    connection.BeginTransaction(); 
    String commandInsert = "INSERT INTO TB_SAMPLE ([NAME]) VALUES ('MR. DUKE')"; 
    OleDbCommand cmd = new OleDbCommand(commandInsert , connection, transaction); 
    cmd.ExecuteNonQuery(); 
    String commandIndentity = "SELECT @@IDENTITY"; 
    cmd = new OleDbCommandcommandIndentity, connection, transaction); 
    Console.WriteLine("New Running No = {0}", (int)cmd.ExecuteScalar()); 
    connection.Commit(); 
}catch(Exception ex){ 
    connection.Rollback(); 
}finally{ 
    connection.Close(); 
} 
-2
CREATE procedure dbo.sp_whlogin 
(
@id nvarchar(20), 
@ps nvarchar(20), 
@curdate datetime, 
@expdate datetime 
) 

AS 
BEGIN 
DECLARE @role nvarchar(20) 
DECLARE @menu varchar(255) 
DECLARE @loginid int 

SELECT  @role = RoleID 
FROM   dbo.TblUsers 
WHERE UserID = @id AND UserPass = @ps 

if @role is not null 
BEGIN 
    INSERT INTO TblLoginLog (UserID, LoginAt, ExpireAt, IsLogin) VALUES (@id, @curdate, @expdate, 1); 
    SELECT @loginid = @@IDENTITY; 
    SELECT @loginid as loginid, RoleName as role, RoleMenu as menu FROM TblUserRoles WHERE RoleName = @role 
END 
else 
BEGIN 
    SELECT '' as role, '' as menu 
END 
END 
GO 
+0

-1 Cơ sở dữ liệu là Jet/ACE. – Fionnuala

0

Câu trả lời ngắn:
1. Tạo hai lệnh từng chấp nhận một truy vấn duy nhất.
2. Truy vấn sql đầu tiên là bản ghi INSERT.
3. Truy vấn sql thứ hai là "SELECT @@ Identity;" trả về AutoNumber.
4. Sử dụng cmd.ExecuteScalar() trả về cột đầu tiên của hàng đầu tiên.
5. Kết quả trả về là giá trị AutoNumber được tạo trong truy vấn chèn hiện tại.

It is referenced from this link. Mã ví dụ như dưới. Lưu ý sự khác biệt cho "Kết nối SAME VS NEW Connection". Kết nối SAME cho đầu ra mong muốn.

class Program 
{ 
    static string path = @"<your path>"; 
    static string db = @"Test.mdb"; 
    static void Main(string[] args) 
    { 
     string cs = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\{1}", path, db); 
     // Using the same connection for the insert and the SELECT @@IDENTITY 
     using (OleDbConnection con = new OleDbConnection(cs)) 
     { 
      con.Open(); 
      OleDbCommand cmd = con.CreateCommand(); 
      for (int i = 0; i < 3; i++) 
      { 
       cmd.CommandText = "INSERT INTO TestTable(OurTxt) VALUES ('" + i.ToString() + "')"; 
       cmd.ExecuteNonQuery(); 

       cmd.CommandText = "SELECT @@IDENTITY"; 
       Console.WriteLine("AutoNumber: {0}", (int)cmd.ExecuteScalar()); 
      } 
      con.Close(); 
     } 
     // Using a new connection and then SELECT @@IDENTITY 
     using (OleDbConnection con = new OleDbConnection(cs)) 
     { 
      con.Open(); 
      OleDbCommand cmd = con.CreateCommand(); 
      cmd.CommandText = "SELECT @@IDENTITY"; 
      Console.WriteLine("\nNew connection, AutoNumber: {0}", (int)cmd.ExecuteScalar()); 
      con.Close(); 
     } 
    } 
} 

này nên tạo ra tự giải thích đầu ra:

AutoNumber: 1 <br> 
AutoNumber: 2 <br> 
AutoNumber: 3 <br> 

New connection, AutoNumber: 0