SQL Server 2008 – IF NOT EXISTS INSERT ELSE UPDATE

我很抱歉,但这是两个部分的问题。

我对SQL非常陌生,正在尝试为我所在的小型办公室开发一个时钟应用程序。现在我正在玩SQL后端,并且对复合语句有疑问。

我被卡住的地方是,如果用户试图计时rest,但从不在开始移位时,SQL需要创build一个新行,而不是更新现有的。

这是我试过的:

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 

我正在使用Visual Studio 2010在本地计算机上连接到SQL Server Express 2008。 我得到一个错误,说“复合语句SQL构造或语句不受支持”。 但是,后面跟着一行消息,当我查看我的时钟表时,看起来就像我期望的那样。 什么是最好的方式来适应这一点?

而这个问题的第二部分在我的WHERE语句中。 是否有一个函数来获取clockDate列中的今天date,而不是必须填充今天的date? 只是想build设前端应用程序提前思考。

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

再次,这给了我想要的结果,但是直到得到一个错误之后“在CURRENT_DATE附近的WHERE子句出错”,无法parsing查询文本。

我希望我已经正确地解释了这一点,并感谢您的帮助!

编辑:

@RThomas @ w00te

好吧,所以clockDate作为date字段和breakOut作为时间(0)字段,应该这样工作吗? 原因我仍然得到“复合语句SQL构造或语句不受支持”。 即使它似乎正在工作,语法错误。

  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 

我的表格结果是:

 clockDate userName clockIn breakOut breakIn clockOut 08/10/2012 test NULL 11:24:38 NULL NULL 

这是我想要的结果,但这个错误令我困惑。 这是一个Visual Studio错误或SQL错误? 我将阅读合并声明,谢谢你们的链接。

乍一看,你原来的尝试似乎很接近。 我假设clockDate是一个date时间字段,所以试试这个:

 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 

请注意,getdate为您提供当前date。 如果你想比较一个date(没有时间)你需要强制转换或时间元素将导致比较失败。


如果clockDate不是datetime字段(只是date),那么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 

正如其他人已经build议你应该看看MERGE语句,但没有人提供了使用它的解决scheme,我添加了我自己的答案这个特定的TSQL构造。 我敢打赌你会喜欢它的。

重要的提示

你的代码在你的if语句not exists(select...)部分有一个错字。 内部select语句只有一个条件,而由于无效的大括号完成,UserName条件被排除在not exists 。 无论如何,你的洞窟太多了。

我认为这是基于你在代码中稍后在update语句中使用两个条件的事实。

让我们继续回答我的问题

SQL Server 2008+支持MERGE语句

MERGE语句是一个美丽的TSQLgem,非常适合“插入或更新”的情况。 在你的情况下,它会看起来类似于下面的代码。 考虑到我声明variables可能存储过程参数(我怀疑)。

 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') 

有一个额外的括号。 我认为如果你删除它就没关系:

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

另外,GETDATE()会把当前的date放在列中,但是如果你不想要这个时间,你将不得不玩一些。 我认为CONVERT(varchar(8),GETDATE(),112)会给你date(而不是时间)部分。

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

应该可能做到这一点。

PS:使用合并声明:)

您需要将其replace为WHERE clockDate = { fn CURRENT_DATE() } AND userName = 'test' 。 请从{ fn CURRENT_DATE() })删除多余的")"