Выберите последнюю строку в таблице SQL - PullRequest
6 голосов
/ 14 июля 2009

Можно ли вернуть последний ряд таблицы в MS SQL Server. Я использую поле автоматического увеличения для идентификатора, и я хочу получить последнее добавленное, чтобы присоединить его к чему-то еще. Есть идеи?

Вот код:

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 ]

24 голосов
/ 14 июля 2009

Небезопасно - может выполняться несколько вставок одновременно, и последняя строка, которую вы получите, может быть не вашей. Вам лучше использовать SCOPE_IDENTITY (), чтобы получить последний ключ, назначенный для вашей транзакции.

19 голосов
/ 14 июля 2009

используя поле автоинкремента ... и я хочу получить последнее добавленное, чтобы присоединить его к чему-то другому.

Ключ здесь " только что добавлен ". Если у вас есть несколько разных пользователей, одновременно обращающихся к БД, я не думаю, что вы хотите, чтобы пользователь А извлек запись, созданную пользователем Б. Это означает, что вы, вероятно, захотите использовать функцию scope_identity() для получения этого идентификатора. вместо того, чтобы сразу же выполнить запрос к таблице.

В зависимости от контекста вам также может понадобиться @@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(); 
}

Смотрите мой ответ на другой вопрос здесь:
получить новый идентификатор записи SQL

Проблема теперь в том, что вы, вероятно, захотите, чтобы последующие операторы sql были в той же транзакции. Вы можете сделать это с помощью клиентского кода, но я считаю, что хранить все это на сервере будет чище. Вы можете сделать это, создав очень длинную строку sql, но я предпочитаю хранимую процедуру на этом этапе.

Я также не фанат метода .AddWithValue() & mdash; Я предпочитаю явно определять типы параметров & mdash; но мы можем оставить это на другой день.

Наконец-то, уже довольно поздно, но я хочу подчеркнуть, что действительно лучше попытаться сохранить все это на БД. Можно выполнять несколько операторов в одной команде sql, и вы хотите уменьшить количество обращений к базе данных, которые вам нужно совершить, и объем данных, которые вам нужно передавать между базой данных и вашим приложением. Это также упрощает правильное выполнение транзакций и позволяет сохранять элементарность там, где они должны быть.

10 голосов
/ 14 июля 2009

использование

  • scope_identity () возвращает последнее значение идентификатора, сгенерированное в этом сеансе, и эту область действия
  • ident_current () возвращает последнее значение идентификатора, сгенерированное для конкретной таблицы в любом сеансе и любой области действия

    выберите ident_current ('yourTableName')

вернет последний идентификатор, созданный другим сеансом.

Большую часть времени вы должны использовать scope_identity () сразу после оператора вставки, например так.

--insert statement
SET @id = CAST(SCOPE_IDENTITY() AS INT)
4 голосов
/ 14 июля 2009
select top 1 * from yourtable order by id desc
1 голос
/ 14 июля 2009

Поскольку респондент использует .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;
        }

ИЗД.

1 голос
/ 14 июля 2009

Я не уверен в вашей версии SQL Server, но посмотрите на предложение OUTPUT оператора INSERT Вы можете захватить набор строк с помощью этого пункта

0 голосов
/ 14 июля 2009

С помощью простого выбора вы можете сделать что-то вроде этого:

SELECT *
FROM table_name
WHERE IDColumn=(SELECT max(IDColum) FROM table_name)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...