SQL: Есть ли какой-либо способ использовать Order By в инструкции update?

#sql #sql-update

#sql #sql-update

Вопрос:

Мне нужно обновить только одну запись в базе данных и назначить ее пользователю. Вот что я делаю:

 UPDATE TOP (1) books SET assigneduser = 1
WHERE bookstatus = 7
AND ((assigneduser is null) or (assigneduser = 1));
  

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

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

Спасибо.

Комментарии:

1. Не могли бы вы сообщить нам, какую СУБД вы используете?

Ответ №1:

Вы должны сначала выбрать нужную запись, затем обновить ее:

 update books
    set assigneduser = 1
where BookPrimaryKeyField = (
    SELETE TOP 1 BookPrimaryKeyField
    from books
    WHERE bookstatus = 7
    AND ((assigneduser is null) or (assigneduser = 1));
)
  

Ответ №2:

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

 UPDATE books SET assigneduser = 1
WHERE BOOKID 
= (SELECT top 1 BOOKID FROM books where
 bookstatus = 7
AND ((assigneduser is null) or (assigneduser = 1)));
  

Комментарии:

1. @Adrian — Я так не думаю, я удалил это из своего sql, это был остаток от copy’n’paste — спасибо!

Ответ №3:

 UPDATE B
SET assigneduser = 1
FROM books B
WHERE bookstatus = 7
AND ((assigneduser is null) or (assigneduser = 1))
and bookid = (select min(bookid) from books where assigneuser is null)
  

Я предположил, что у вас есть столбец идентификатора bookid.

Это позволяет получить наименьший идентификатор книги без назначенного пользователя и присоединить его обратно к книгам, чтобы получить единственную запись (как часть b), которую вы затем можете обновить.

Ответ №4:

Посмотрите на http://msdn.microsoft.com/en-us/library/ms177523.aspx.

Если вы должны использовать TOP для применения обновлений в значимой хронологии, вы должны использовать TOP вместе с ORDER BY в инструкции subselect . Следующий пример обновляет часы отпуска 10 сотрудников с самыми ранними датами найма.

 UPDATE HumanResources.Employee
SET VacationHours = VacationHours   8
FROM (SELECT TOP 10 BusinessEntityID FROM HumanResources.Employee
     ORDER BY HireDate ASC) AS th
WHERE HumanResources.Employee.BusinessEntityID = th.BusinessEntityID;
GO
  

Ответ №5:

Вероятно, было бы проще разбить это на 2 части

     DECLARE @bookid as INT

    SELECT TOP (1) @bookid = id FROM books
    WHERE bookstatus = 7
    AND ((assigneduser is null) or (assigneduser = 1))
    ORDER BY bookname

    UPDATE books SET assigneduser = 1
    WHERE id = @bookid
  

Ответ №6:

Есть способ обойти это, используя следующий подзапрос:

 UPDATE books SET assigneduser=1
AND ((assigneduser is null) or (assigneduser = 1))
AND bookname in (SELECT TOP 1 bookname FROM Table ORDER BY bookname DESC) 
  

Комментарии:

1. @Adrian: Просто из любопытства — как вы думаете, в чем ошибка UPDATE TOP(1) ? Кажется, у меня это работает (при условии, что это SQLServer)

2. @a1ex07, это будет зависеть от того, какую версию базы данных вы используете, будет ли это работать.

3. У меня это также работает в SQL Server 2008. Однако OP не указал RDMS. Утверждать, что это работает, рискованно. Вот почему я спросил «вы уверены», вместо «это неправильно». Кстати, я не знаю, будет ли это работать на SQL Server 2005 или меньше

4. @Adrian: Да, я понимаю… У меня нет SQLServer 2005, но, согласно msdn, он также должен работать. В любом случае, то, что вы говорите, имеет смысл — это может не работать в более старых версиях или на разных RDMS.

5. Вот и все, ребята. Кроме того, при использовании TOP важен порядок, о чем спрашивает OP: как убедиться, что вы обновляете правильную запись? Кстати, мой ответ делает это в стиле ANSI SQL.

Ответ №7:

Поскольку update не возвращает никаких данных, а ‘order by’ сортирует результирующий набор, ORDER BY работать не над чем, и то, что вы ищете, невозможно.

Если вы хотите назначить только одну книгу, вы можете обновить, используя join в top 1 из вашего набора.

 UPDATE b0 SET assigneduser = 1
FROM b0 
  INNER JOIN
(SELECT top 1 id FROM books
WHERE user = 1 OR user is null
AND status =7)  b1 ON b1.id = b0.id
  

или, возможно, менее загадочный

 UPDATE user SET assigneduser = 1
WHERE id IN
(SELECT top 1 id FROM books
WHERE user = 1 OR user is null
AND status =7)  b1 ON b1.id = b0.id
  

Является ли эта стратегия надежной в отношении параллелизма, зависит от семантики транзакции.