简体   繁体   English

“Pop”记录 - 在同一语句中选择和删除(SQL Server 2005)

[英]“Pop” Record — Select And Delete In The Same Statement (SQL Server 2005)

I have a C# application that is used by about a dozen employees simultaneously. 我有一个C#应用程序,大约有十几个员工同时使用它。 It simply SELECTs the top record from a SQL Server 2005 table, DELETE it, then displays the data on a form. 它只是从SQL Server 2005表中选择顶级记录,删除它,然后在表单上显示数据。
As soon as the record is selected it needs to be deleted so 2 ppl don't grab and work on the same record. 一旦选择了记录,就需要将其删除,因此2个人不会抓取并处理同一记录。
Fairly Straight Forward... 非常坦率的...

I found a suggestion a while ago (cant find the site i got it from, sorry) to do a SELECT and DELETE in the same statement and execute a SqlCommand.ExecuteReader() with this "compound" statement: 我刚才发现了一个建议(无法找到我得到它的网站,抱歉)在同一个语句中执行SELECT和DELETE并使用这个“复合”语句执行SqlCommand.ExecuteReader()

SELECT TOP 1 * 
FROM Call_Table 
WHERE Call_Table.hold_call_till <= GetDate() 
ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC;
DELETE 
FROM Call_Table
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                           FROM Call_Table 
                           WHERE Call_Table.hold_call_till <= GetDate() 
                           ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC);

Its been working quite well so far, but i feel like i've just been lucky. 到目前为止它一直运作良好,但我觉得我很幸运。 We're hiring about 5 new ppl, and i would like to totally sure this will continue to work. 我们正在招聘5个新人,我想完全确定这将继续有效。

Im interested to hear the opinion of more seasoned vets in this area. 我很想听听这个地区更多经验丰富的兽医的意见。

Should I stick with the "If its not broken, dont fix it" approach?? 我应该坚持“如果没有破坏,不解决它”的方法? Or should I step up my game and use some kind of record_locks or stored procs?? 或者我应该加强我的游戏并使用某种record_locks或存储过程?

Any suggestions will be openly accepted. 任何建议都将被公开接受。 I can supply more info about the table or C# application if necessary. 如有必要,我可以提供有关表或C#应用程序的更多信息。

I would suggest using some sort of optimistic concurrency control instead. 我建议使用某种乐观的并发控制 Do not delete the record, but instead store a timestamp (or some other versioning technique) which will be grabbed on select. 不要删除记录,而是存储将在select上抓取的时间戳(或其他一些版本控制技术)。 Then, if the user edits something you can check to make sure the timestamp has not changed. 然后,如果用户编辑了某些内容,您可以检查以确保时间戳没有更改。 If it has, then prompt the user and reload the new data. 如果有,则提示用户并重新加载新数据。 If it has not, then save the data, and update the timestamp so that anybody else with the data will not overwrite your changes. 如果没有,则保存数据并更新时间戳,以便其他拥有数据的人不会覆盖您的更改。

Microsoft's article on optimistic concurrency 微软关于乐观并发的文章

Here is my version of a graphical example (using a numbering system instead of timestamps for the versioning) 这是我的版本的图形示例(使用编号系统而不是版本控制的时间戳)

Name|PhoneNum|Version
Joe |123-1234|1
  • UserA and UserB pull up Joe's data in your UI UserA和UserB在您的UI中提取Joe的数据

  • UserA modifies and saves Joe UserA修改并保存Joe

Now the table looks like this: 现在表格看起来像这样:

Name|PhoneNum|Version
Joe |555-5555|2
  • UserB modifies the Version 1 of Joe's data and saves. UserB修改Joe的数据版本1并保存。 The save sees that the Version is now 2 and prompts UserB that the data has changed. 保存看到版本现在为2并提示UserB数据已更改。

UPDATE UPDATE

You have two options if the row cannot be accessed while the User is reading it. 如果在用户正在读取行时无法访问该行,则有两个选项。

  • You can do what you are already doing, but you do not need the select...delete due to OUTPUT (as suggested above already). 您可以执行您正在执行的操作,但由于OUTPUT (如上所述),您不需要选择...删除。 With this, you can delete and get the value. 有了这个,您可以删除并获取值。

Code: 码:

DECLARE @CallInfo TABLE (/*Call_Table Schema*/)

DELETE Call_Table
OUTPUT DELETED.* INTO @CallInfo 
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                       FROM Call_Table 
                       WHERE Call_Table.hold_call_till <= GetDate() 
                       ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC)

--The @CallInfo will have the info that you just deleted, so pass that back to the UI
SELECT * FROM @CallInfo
  • You can add a lock column (using the user id of the person locking) that you update right before you select the data. 您可以在选择数据之前添加更新的锁定列(使用人员锁定的用户ID)。 The only thing you then need to worry about it if the user crashes or does something where they do not reset the lock. 如果用户崩溃或做了不重置锁定的事情,那么你唯一需要担心的是它。 I have used this system in the past, but the complexity might not be worth it if most of the time the data is deleted. 我过去曾使用过这个系统,但如果大多数时候删除数据,复杂性可能不值得。 I find this more useful if you need to simply update data. 如果您只需更新数据,我发现这更有用。 You can add logic that says, if the same user tries to get the data again, then let them since it was probably a crash. 你可以添加逻辑,如果同一个用户试图再次获取数据,那么就让它们,因为它可能是一个崩溃。 Otherwise, you then need to create an unlocking system. 否则,您需要创建一个解锁系统。

看起来像你需要的是暗示UPDLOCK加上这里描述的READPAST提示http://www.adathedev.co.uk/2010/03/queue-table-processing-in-sql-server.html

You can use the OUTPUT clause of the DELETE statement to delete a row and return it in the same statement, eg: 您可以使用DELETE语句OUTPUT子句删除行并在同一语句中返回它,例如:

delete queue output deleted.* where id = (select min(id) from queue)

Assuming you have a table that looks something like this 假设你有一个看起来像这样的表

create table Queue(
    ID bigint identity not null primary key,
    Data varchar(max)
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM