2012-08-10 70 views
53

我很抱歉,但这是一个两部分问题。SQL Server 2008 - 如果不存在INSERT ELSE UPDATE

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

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

这里是我的尝试:

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列中获取今天的日期,而不是必须填充今天的日期?试图为构建前端应用程序提前考虑。

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

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

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

编辑:

@RThomas @ w00te

OK,所以与clockDate如日期字段和分组的时间(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错误?我会阅读合并声明,谢谢你们的链接。

+12

检查出[合并](http://technet.microsoft.com/en-us/library/bb510625.aspx)语句。 – 2012-08-10 17:32:30

+2

尽管我在下面的答案,我同意其他人关于合并声明是一个很好的方式来处理插入/更新情况,当你不确定值是否已经存在或没有。以下是我重新发布的合并声明的演练。 http://stackoverflow.com/questions/10218101/extremely-simple-t-sql-merge-example-needed-to-help-comprehension/10219581#10219581如果你想了解更多关于它是如何工作的。 – RThomas 2012-08-10 18:06:48

+0

这就是MERGE语句的用法!检查出来http://technet.microsoft.com/en-us/library/bb510625.aspx – curiousBoy 2013-08-16 21:25:13

回答

3
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()将会把当前日期在列,但如果你不想要的时候,你必须打一点。我认为CONVERT(varchar(8),GETDATE(),112)会给你日期(而不是时间)部分。

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

应该可能做到这一点。

PS:使用merge声明:)

2

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

+0

对不起,这只是我的一个错字。我确实在我的SQL查询窗口中是正确的。 – tmhalbert 2012-08-10 17:50:11

+0

谢谢,这对初学者很有帮助。 – 2017-08-06 11:11:00

46

乍一看,您的原始尝试看起来非常接近。我假设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 

注意GETDATE给你当前的日期。如果您试图比较日期(没有时间),则需要投射或时间元素会导致比较失败。


如果clockDate没有时间字段(只是日期),那么SQL引擎会为你做它 - 没有必要投上一组/插入语句。

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 
+0

clockDate是'date'数据类型不是'datetime'。对不起,没有澄清。 – tmhalbert 2012-08-10 17:41:27

+0

你可以放下演员陈述,然后......我会添加到我的文章。 – RThomas 2012-08-10 17:42:32

+0

哦,breakOut是'time(0)'字段 – tmhalbert 2012-08-10 17:47:04

27

正如其他人建议,你应该看看MERGE语句,但没有人使用它,我将我自己的答案与此特定TSQL结构提供了解决方案。我敢打赌你会喜欢它的。

重要提示

您的代码有一个错字在not exists(select...)属于你if声明。内部select声明只有一个where条件,而由于无效大括号完成而导致not exists中排除了用户名条件。无论如何,你的洞窟太多了。

我认为这是基于您在代码中稍后在update声明中使用两个where条件的事实。

让我们继续我的答案......

的SQL Server 2008+支持MERGE语句

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

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()); 
+1

我有一些储备找到MERGE美丽。 – Steve 2017-11-03 17:39:36

相关问题