0

我是 sql 新手。我在数据库中添加了 2 个新表。第一个的主键是另一个的外键。键的类型是整数。现在我想在代码中生成键并将其分配给新数据,以便表的不同行之间的关联是正确的。如何确保密钥的唯一性并从数据库中获取最新的密钥,以便在保存时不会出错。

如果我使用了 guid,那么我会为主键分配一个新的 guid,然后将其分配给另一个表中的外键。还有多个客户端和一台服务器正在保存数据。

要在两个表中插入的数据是在 c# 代码中决定的,而不是从插入到主表中的行中派生的。即使在 db 中获取 id,那么行之间的关系也应该以某种形式从代码中存储,因为之后它就会丢失。

4

2 回答 2

16

唯一可行的方法是使用INT IDENTITYSQL Server 数据库提供的方法。相信我 - 你不想自己尝试做这件事!

只需使用

CREATE TABLE dbo.YourTableOne(ID INT IDENTITY(1,1),  ...other columns...)

并完成它。

在您的第一个表中插入一行后,您可以像这样检索标识列的值:

-- do the insert into the first table
INSERT INTO dbo.YourTableOne(Col1, Col2, ...., ColN)
VALUES (Val1, Val2, ...., ValN)

DECLARE @NewID INT

-- get the newly inserted ID for future use
SELECT @NewID = SCOPE_IDENTITY()

-- insert into the second table, use first table's new ID for your FK column
INSERT INTO dbo.YourTableTwo (FKColumn, ......) VALUES(@NewID, ......)

更新:如果您需要在第一个表中插入多行并捕获多个生成ID的值,请使用OUTPUT子句:

-- declare a table variable to hold the data
DECLARE @InsertedData TABLE (NewID INT, ...some other columns as needed......)

-- do the insert into the first table
INSERT INTO dbo.YourTableOne(Col1, Col2, ...., ColN)
OUTPUT Inserted.ID, Inserted.Col1, ..., Inserted.ColN INTO @InsertedData(NewID, Col1, ..., ColN)
VALUES (Val1, Val2, ...., ValN)

然后从那里去。您可以从新插入的行中获取任何值到临时表变量中,然后您可以决定将哪些新 ID 值用于第二个表的哪些行

于 2013-07-30T16:11:13.727 回答
2

正如@marc_s 所说,使用数据库管理的密钥更可行。但是在数据库负载不大的情况下,例如同时工作的用户很少,我将使用另一种更简单的方法。那是我得到最后一个id,我尝试添加新记录,如果遇到重复错误,我会再试一次。我将我的应用程序限制为 3 次试验,每次试验之间有 300 毫秒的超时。不要忘记这种方法有严重的局限性。在我的应用程序中,用户很少,工作量很低,并且连接是本地连接,所以这会做得很好。也许在其他应用程序中您需要调整延迟,在某些情况下,该方法可能完全失败。这是代码,我有两个表,InvoicesInvoices_Items它们相关的列是invoice_id

        byte attempts = 0;

      tryagain:  //Find last invoice no

        OleDbCommand command = new OleDbCommand("SELECT MAX(invoice_id) FROM Invoices"
                 , myconnection);
            int last_invoice_id = 0;
            try
            {
                last_invoice_id = (int)command.ExecuteScalar();
            }
            catch (InvalidCastException) { };

           // text_invoice_number.Text = Convert.ToString(last_invoice_id + 1);

            try
            {
                command = new OleDbCommand(@"INSERT INTO Invoices
      (invoice_id,patient_id,visit_id,issue_date,invoice_to,doctor_id,assistant_id)
     VALUES(?,?,?,?,?,?,?)",myconnection);
   // We use last_invoice_id+1 as primary key
   command.Parameters.AddWithValue("@invoice_id",last_invoice_id+1);
            // I will add other parameters here (with the exact order in query)
                command.ExecuteNonQuery();
            }
            catch (Exception ex){
                attempts++;
                if (attempts <= 3)  // 3 attempts
                {
                    System.Threading.Thread.Sleep(300); // 300 ms second delay
                    goto tryagain;
                }
                else
                {
                    MessageBox.Show("Can not add invoice to database, " + ex.Message,   "Unexpected error!"
                        , MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }

        for (int i = 0; i <= listInvoiceItems.Count-1; i++)
        {
               command = new OleDbCommand(@"INSERT INTO Invoices_Items
                                 (invoice_id,quantity,product,price,amount,item_type)
                                        VALUES(?,?,?,?,?,?)",myconnection);
       // Now we use our stored last_invoice_id+1 as foreign key
             command.Parameters.AddWithValue("@invoice_id",last_invoice_id+1); 
         // Add other Invoice Items parameters here (with the exact order in query)
        command.ExecuteNonQuery();
        }
于 2013-08-12T07:12:35.800 回答