选择SQL表中的最后一行

时间:2009-07-14 15:28:16

标签: sql sql-server

是否可以在MS SQL Server中返回表的最后一行。 我正在为ID使用自动增量字段,我想要添加最后一个用于加入其他内容的字段。有什么想法吗?

以下是代码:

const string QUERY = @"INSERT INTO Questions (ID, Question, Answer, CategoryID, Permission) " 
                   + @"VALUES (@ID, @Question, @Answer, @CategoryID, @Permission) "; 

using (var cmd = new SqlCommand(QUERY, conn)) 
{ 
    cmd.Parameters.AddWithValue("@Question", question); 
    cmd.Parameters.AddWithValue("@Answer", answer); 
    cmd.Parameters.AddWithValue("@CategoryID", lastEdited);
    cmd.Parameters.AddWithValue("@Permission", categoryID);
    cmd.ExecuteNonQuery(); 
}

7 个答案:

答案 0 :(得分:24)

不安全 - 可能会同时进行多个插入,而您获得的最后一行可能不属于您。您最好使用SCOPE_IDENTITY()来获取为您的交易分配的最后一个密钥。

答案 1 :(得分:19)

  

使用自动增量字段...我想要添加最后一个用其他东西加入它。

这里的关键是“刚刚添加”。如果你有一堆不同的用户同时点击数据库,我认为你不希望用户A检索用户B创建的记录。这意味着你可能想要使用scope_identity()函数来获取该id而不是立即再次在表上运行查询。

根据上下文,您可能还需要@@identity(包括触发器)或ident_current('questions')(仅限于特定表,但不包括特定范围)。但scope_identity()几乎总是正确使用。


以下是一个例子:

DECLARE @NewOrderID int

INSERT INTO TABLE [Orders] (CustomerID) VALUES (1234)

SELECT @NewOrderID=scope_identity()

INSERT INTO TABLE [OrderLines] (OrderID, ProductID, Quantity) 
    SELECT @NewOrderID, ProductID, Quantity
    FROM [ShoppingCart]
    WHERE CustomerID=1234 AND SessionKey=4321

根据您发布的代码,您可以执行以下操作:

// don't list the ID column: it should be an identity column that sql server will handle for you
const string QUERY = "INSERT INTO Questions (Question, Answer, CategoryID, Permission) " 
                   + "VALUES (@Question, @Answer, @CategoryID, @Permission);"
                   + "SELECT scope_identity();"; 

int NewQuestionID;
using (var cmd = new SqlCommand(QUERY, conn)) 
{ 
    cmd.Parameters.AddWithValue("@Question", question); 
    cmd.Parameters.AddWithValue("@Answer", answer); 
    cmd.Parameters.AddWithValue("@CategoryID", lastEdited);
    cmd.Parameters.AddWithValue("@Permission", categoryID);
    NewQuestionID = (int)cmd.ExecuteScalar(); 
}

在此处查看我对另一个问题的回答:
get new SQL record ID

现在的问题是你可能希望后续的sql语句在同一个事务中。您可以使用客户端代码执行此操作,但我发现在服务器上保持更清晰。你可以通过构建一个非常长的sql字符串来做到这一点,但我倾向于在这一点上更喜欢存储过程。

我也不是.AddWithValue()方法的粉丝 - 我更喜欢明确定义参数类型 - 但我们可以将其留待另一天。

最后,现在已经很晚了,但我想强调的是,尝试将这一切保留在db上真的更好。在一个sql命令中运行多个语句是可以的,并且您希望减少需要对数据库进行的往返次数以及在数据库和应用程序之间来回传递所需的数据量。它还使得更容易获得正确的交易,并将事物保持原状。

答案 2 :(得分:10)

使用

  • scope_identity()返回此会话和此范围中生成的最后一个标识值
  • ident_current()返回在任何会话和任何范围内为特定表生成的最后一个标识值

    选择ident_current('yourTableName')

将返回由其他会话创建的最后一个标识。

大多数情况下,你应该在插入语句之后立即使用scope_identity()。

--insert statement
SET @id = CAST(SCOPE_IDENTITY() AS INT)

答案 3 :(得分:4)

select top 1 * from yourtable order by id desc

答案 4 :(得分:1)

我不确定您的SQL Server版本,但查找INSERT语句的OUTPUT子句。您可以使用此子句

捕获一组行

答案 5 :(得分:1)

由于提问者正在使用.NET,这里有一个如何做的修改示例。 (我从插入列表中删除了ID,因为它是自动增量 - 原始示例会失败。我还假设ID是一个SQL int,而不是bigint。)

        const string QUERY = @"INSERT INTO Questions (Question, Answer, CategoryID, Permission) "
                           + @"VALUES (@Question, @Answer, @CategoryID, @Permission);"
                           + @"SELECT @ID = SCOPE_IDENTITY();";

        using (var cmd = new SqlCommand(QUERY, conn)) 
        { 
            cmd.Parameters.AddWithValue("@Question", question); 
            cmd.Parameters.AddWithValue("@Answer", answer); 
            cmd.Parameters.AddWithValue("@CategoryID", lastEdited);
            cmd.Parameters.AddWithValue("@Permission", categoryID);
            cmd.Parameters.Add("@ID", System.Data.SqlDbType.Int).Direction = ParameterDirection.Output;
            cmd.ExecuteNonQuery();

            int id = (int)cmd.Parameters["@ID"].Value;
        }

已编辑:我还建议考虑使用LINQ to SQL而不是手工编写SqlCommand对象 - 对于许多常见场景来说,它更好(代码更快,更易于使用)。

答案 6 :(得分:-1)

通过简单的选择,您可以执行以下操作:

SELECT *
FROM table_name
WHERE IDColumn=(SELECT max(IDColum) FROM table_name)