简体   繁体   English

SQL Server 2008-如果不存在则插入其他更新

[英]SQL Server 2008 - IF NOT EXISTS INSERT ELSE UPDATE

I apologize, but this is kind of a two part question. 我很抱歉,但这是一个分为两个部分的问题。

I'm extremely new to SQL and am trying to develop a time clock application for the small office that I work in. I'm playing around with the SQL backend right now and have a question about compound statements. 我对SQL非常陌生,正在尝试为我工作的小型办公室开发一个时钟应用程序。我现在正在使用SQL后端,并对复合语句有疑问。

Where I'm stuck is if a user tries to clock out for break but never clocked in at the start of the shift, SQL needs to create a new row rather than update an existing. 我遇到的问题是,如果用户尝试暂停工作,但从未在轮班开始时提出要求,则SQL需要创建新行,而不是更新现有行。

Here is what I tried: 这是我尝试过的:

    IF NOT EXISTS(SELECT * FROM Clock WHERE clockDate = '08/10/2012') AND userName = 'test')
    BEGIN
        INSERT INTO Clock(clockDate, userName, breakOut)
        VALUES({ fn NOW() }, 'test', { fn NOW() })
    END
    ELSE
    BEGIN
        UPDATE Clock
        SET breakOut = { fn NOW() }
        WHERE (clockDate = '08/10/2012') AND (userName = 'test')
    END

I'm using Visual Studio 2010 to do this connected to SQL Server Express 2008 on my local machine. 我正在使用Visual Studio 2010将其连接到本地计算机上的SQL Server Express 2008。 I get an error that says "The Compound statement SQL construct or statement is not supported." 我收到一条错误消息:“不支持Composite语句SQL构造或语句。” However, that is followed by a message that 1 row has been affected, and when I view my Clock table it looks just like what I expect it to look like. 但是,这之后会出现一条消息,指出1行已受到影响,当我查看Clock表时,它看起来就像我期望的样子。 What is the best way to acclompish this? 做到这一点的最佳方法是什么?

And my second part of this question is in my WHERE statements. 我的第二部分问题在我的WHERE语句中。 Is there a function to get today's date in the clockDate column rather than have to populate today's date? 是否有一个函数可以在clockDate列中获取今天的日期,而不必填充今天的日期? Just trying to think ahead for building the front end application. 只是尝试为构建前端应用程序进行前瞻性思考。

    IF NOT EXISTS(SELECT * FROM Clock WHERE clockDate = { fn CURRENT_DATE() }) AND userName = 'test')

Again, this gives me the results I want, but not until after getting an error "Error in WHERE clause near 'CURRENT_DATE'. Unable to parse query text." 再次,这给了我想要的结果,但是直到出现错误“ CURRENT_DATE附近的WHERE子句中的错误。无法解析查询文本”之后,我才得到结果。

I hope I have explained this properly, and thank you for your help!! 我希望我已经正确解释了这一点,并感谢您的帮助!

EDIT: 编辑:

@RThomas @w00te @RThomas @ w00te

OK, so with the clockDate as a date field and breakOut as a time(0) field, should this work? 好的,因此使用clockDate作为日期字段,将breakOut作为time(0)字段,是否可以正常工作? Cause I'm still getting a "The Compound statement SQL construct or statement is not supported." 原因我仍然收到“不支持Composite语句SQL构造或语句”。 Syntax error even though it seems to be working. 语法错误,即使它似乎正在工作。

    IF NOT EXISTS (SELECT * FROM Clock WHERE (clockDate = GETDATE()) AND (userName = 'test'))
    BEGIN
        INSERT INTO Clock(clockDate, userName, breakOut)
        Values(GETDATE(), 'test', GETDATE())
    END
    ELSE
    BEGIN
        UPDATE Clock
        SET breakOut = GETDATE()
        WHERE (clockDate = GETDATE()) AND (userName = 'test')
    END

My table results are: 我的表结果是:

clockDate  userName  clockIn  breakOut  breakIn  clockOut

08/10/2012  test      NULL    11:24:38   NULL     NULL

This is the result I want but this error confuses me. 这是我想要的结果,但是此错误使我感到困惑。 Is this a Visual Studio error or a SQL error? 这是Visual Studio错误还是SQL错误? And I'll read up on Merge Statements, thank you both for the links. 我将阅读合并声明,谢谢你们的链接。

At first glance your original attempt seems pretty close. 乍一看,您最初的尝试似乎非常接近。 I'm assuming that clockDate is a DateTime fields so try this: 我假设clockDate是一个DateTime字段,所以请尝试以下操作:

IF (NOT EXISTS(SELECT * FROM Clock WHERE cast(clockDate as date) = '08/10/2012') 
    AND userName = 'test') 
BEGIN 
    INSERT INTO Clock(clockDate, userName, breakOut) 
    VALUES(GetDate(), 'test', GetDate()) 
END 
ELSE 
BEGIN 
    UPDATE Clock 
    SET breakOut = GetDate()
    WHERE Cast(clockDate AS Date) = '08/10/2012' AND userName = 'test'
END 

Note that getdate gives you the current date. 请注意,getdate为您提供当前日期。 If you are trying to compare to a date (without the time) you need to cast or the time element will cause the compare to fail. 如果尝试与日期(无时间)进行比较,则需要强制转换,否则时间元素将导致比较失败。


If clockDate is NOT datetime field (just date), then the SQL engine will do it for you - no need to cast on a set/insert statement. 如果clockDate不是日期时间字段(仅日期),则SQL引擎将为您执行此操作-无需强制转换为set / insert语句。

IF (NOT EXISTS(SELECT * FROM Clock WHERE clockDate = '08/10/2012') 
    AND userName = 'test') 
BEGIN 
    INSERT INTO Clock(clockDate, userName, breakOut) 
    VALUES(GetDate(), 'test', GetDate()) 
END 
ELSE 
BEGIN 
    UPDATE Clock 
    SET breakOut = GetDate()
    WHERE clockDate = '08/10/2012' AND userName = 'test'
END 

As others have pointed out, the merge statement is another way to tackle this same logic. 正如其他人指出的那样,merge语句是解决此逻辑的另一种方法。 However, in some cases, especially with large data sets, the merge statement can be prohibitively slow, causing a lot of tran log activity. 但是,在某些情况下,尤其是对于大型数据集,merge语句可能会非常慢,从而导致大量的tran日志活动。 So knowing how to logic it out as shown above is still a valid technique. 因此,知道如何如上所示进行逻辑运算仍然是有效的技术。

As others have suggested that you should look into MERGE statement but nobody provided a solution using it I'm adding my own answer with this particular TSQL construct. 正如其他人所建议的那样,您应该研究MERGE语句,但是没有人提供使用它的解决方案,我为此特定的TSQL构造添加了自己的答案。 I bet you'll like it. 我敢打赌你会喜欢的。

Important note 重要的提示

Your code has a typo in your if statement in not exists(select...) part. 您的代码中if语句中not exists(select...)错字not exists(select...) Inner select statement has only one where condition while UserName condition is excluded from the not exists due to invalid brace completion. 内部select语句只有一个条件, where由于无效的大括号补全而将UserName条件not exists条件中排除。 In any case you cave too many closing braces. 无论如何,您会使太多的右括号掉落。

I assume this based on the fact that you're using two where conditions in update statement later on in your code. 我基于您稍后在代码中的update语句中使用两个where条件这一事实来进行假设。

Let's continue to my answer... 让我们继续我的答案...

SQL Server 2008+ support MERGE statement SQL Server 2008+支持MERGE语句

MERGE statement is a beautiful TSQL gem very well suited for "insert or update" situations. MERGE语句是一个非常漂亮的TSQL gem,非常适合“插入或更新”情况。 In your case it would look similar to the following code. 在您的情况下,它看起来类似于以下代码。 Take into consideration that I'm declaring variables what are likely stored procedure parameters (I suspect). 考虑到我在声明变量,可能是什么存储过程参数(我怀疑)。

declare @clockDate date = '08/10/2012';
declare @userName = 'test';

merge Clock as target
using (select @clockDate, @userName) as source (ClockDate, UserName)
on (target.ClockDate = source.ClockDate and target.UserName = source.UserName)
when matched then
    update
    set BreakOut = getdate()
when not matched then
    insert (ClockDate, UserName, BreakOut)
    values (getdate(), source.UserName, getdate());
IF NOT EXISTS(SELECT * FROM Clock
WHERE clockDate = '08/10/2012') AND userName = 'test')

Has an extra parenthesis. 有一个额外的括号。 I think it's fine if you remove it: 我认为如果删除它就可以了:

IF NOT EXISTS(SELECT * FROM Clock WHERE
clockDate = '08/10/2012' AND userName = 'test')

Also, GETDATE() will put the current date in the column, though if you don't want the time you'll have to play a little. 同样,GETDATE()会将当前日期放在该列中,尽管如果您不希望花费时间,则必须花一点时间。 I think CONVERT(varchar(8), GETDATE(), 112) would give you just the date (not time) portion. 我认为CONVERT(varchar(8),GETDATE(),112)只会给您日期(而不是时间)部分。

IF NOT EXISTS(SELECT * FROM Clock WHERE
clockDate = CONVERT(varchar(8), GETDATE(), 112)
AND userName = 'test')

should probably do it. 应该应该这样做。

PS: use a merge statement :) PS:使用合并语句:)

You need to replace it as WHERE clockDate = { fn CURRENT_DATE() } AND userName = 'test' . 您需要将其替换为WHERE clockDate = { fn CURRENT_DATE() } AND userName = 'test' Please remove extra ")" from { fn CURRENT_DATE() }) 请从{ fn CURRENT_DATE() })删除多余的")"

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

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