SQL stored procedure IF EXISTS UPDATE ELSE INSERT - sql

OK. I got a lot of help here earlier working with a SQL backend to a simple ... just not for me :( ... time clock solution for the small office I work in, so I'm back for more!
My table I'm currently working with consists of 6 columns:
clockDate date not null PK
userName varchar(50) not null PK
clockIn time(0)
breakOut time(0)
breakIn time(0)
clockOut time(0)
I though I had figured out my IF NOT EXISTS INSERT ELSE UPDATE statement from my last question, but now I'm trying to use it in a Stored Procedure, rather than a plain query window, with no success.
Basically a user clocking in is a no-brainer. However, if the user doesn't clock in, but they clock out for lunch, the statement needs to create the row instead of updating an existing row. Ok so here's my stored procedure:
ALTER PROCEDURE dbo.BreakOut
(
#userName varchar(50)
)
AS
IF EXISTS (SELECT * FROM Clock WHERE clockDate = GETDATE() AND userName = #userName)
BEGIN
UPDATE Clock SET breakOut = GETDATE()
WHERE clockDate = GETDATE() AND userName = #userName
END
ELSE
BEGIN
INSERT INTO Clock (clockDate, userName, breakOut)
VALUES (GETDATE(), #userName, GETDATE())
END
Here's my problem... If the user DID clock in for the day I get a primary key violation because the stored procedure is still trying to run the INSERT part of the statement and never runs the UPDATE line. I've tried it flipped with an IF NOT EXISTS as well with the same result. What's the trick to get IF-ELSE to work in a stored procedure? Can this be done they way I'm thinking or do I have to study Merge statement? My plan is to run the stored procedures from a simple Visual Basic program on each workstation. Maybe I'm getting in over my head :( To bad my boss is too cheap to just buy a time clock solution!
EDIT:
Thank you ALL for your help!! I'm falling in love with this site, questions get answers SO FAST!!! Here is my working stored procedure:
ALTER PROCEDURE dbo.BreakOut
(
#userName varchar(50)
)
AS
IF EXISTS (SELECT * FROM Clock WHERE DateDiff(dd, GetDate(),clockDate) = 0 AND userName = #userName)
BEGIN
UPDATE Clock SET breakOut = GETDATE()
WHERE DateDiff(dd, GetDate(),clockDate) = 0 AND userName = #userName
END
ELSE
BEGIN
INSERT INTO Clock (clockDate, userName, breakOut)
VALUES (GETDATE(), #userName, GETDATE())
END
Is this proper, or could it be improved more? Again Thank You ALL SO MUCH!!!

This is probably the problem right here: WHERE clockDate = GETDATE()
GetDate returns the current date AND the current time, which wouldn't match up with clockDate. You can compare the dates with DateDiff instead:
WHERE DateDiff(dd, GetDate(),clockDate) = 0

Your problem would appear to be the following:
Let's imagine the user clocked in at 09:00
A record like the following might exist:
ClockDate userName clockIn breakOut breakIn clockOut
12/08/2012 joe 09:00 NULL NULL NULL
Now your IF statement is doing this:
SELECT * FROM Clock WHERE clockDate = "20120812 17:24:13" AND userName = #userName
i.e. this record wont exist.
Instead, try this:
IF EXISTS (SELECT * FROM Clock WHERE clockDate = DATEADD(D, 0, DATEDIFF(D, 0, GETDATE())) AND userName = #userName)
You also need to make sure you are storing clockDate as just the date portion of GETDATE(), otherwise, you would need to adjust your query like so:
IF EXISTS (SELECT * FROM Clock WHERE DATEADD(D, 0, DATEDIFF(D, 0, clockDate)) = DATEADD(D, 0, DATEDIFF(D, 0, GETDATE())) AND userName = #userName)

Your update will never run because GETDATE returns a date and time.
http://msdn.microsoft.com/en-us/library/ms188383.aspx

CREATE PROCEDURE `SP_GENRE_SELECT`(
IN _Id INTEGER,
IN _Name VARCHAR(50),
IN _account VARCHAR (50),
IN _Password VARCHAR (50),
IN _LastConnexionDate DATETIME,
IN _CreatedDate DATETIME,
IN _UpdatedDate DATETIME,
IN _CreatedUserId INTEGER,
IN _UpdatedUserId INTEGER,
IN _Status TINYINT
)
BEGIN
SELECT *
FROM user
WHERE Id LIKE IF(_Id IS NULL,'%',CAST(_Id AS VARCHAR(50)))
AND
Name LIKE IF(_Name IS NULL,'%',CONCAT('%',_Name,'%'))
AND
Account LIKE IF(_Account IS NULL,'%',CONCAT('%',_Account,'%'))
AND
LastConnexionDate LIKE IF(_LastConnexionDate IS NULL,'%',CONCAT('%',CAST(LastConnexionDate AS VARCHAR(50),'%')))
AND
CreatedDate LIKE IF(_CreatedDate IS NULL,'%',CONCAT('%',CAST(_CreatedDate AS VARCHAR(50),'%')))
AND
UpdatedDate LIKE IF(_UpdatedDate IS NULL,'%',CONCAT('%',CAST(_UpdatedDate AS VARCHAR(50),'%')))
AND
CreatedUserID LIKE IF(_CreatedUserID IS NULL,'%',CONCAT('%',CAST(_CreatedUserID AS VARCHAR(50),'%')))
AND
UpdatedUserID LIKE IF(_UpdatedUserID IS NULL,'%',CONCAT('%',CAST(_UpdatedUserID AS VARCHAR(50),'%')))
AND
Status LIKE IF(_Status IS NULL,'%',CAST(_Status AS VARCHAR(50),'%'))
END

Related

SQL Server DATETIME, automatically fill at exactly 10pm of the day when not fill before 10pm of the same day

Table structure:
ID int
status varchar (10)
DATE_CREATED datetime
DATE_CLOSED datetime
Stored procedure for filling DATE_CREATED:
CREATE PROCEDURE [dbo].[...]
#ID INT,
#STATUS VARCHAR(10) = 'Open',
#DATE_CREATED DATETIME = NULL
AS
SET NOCOUNT ON
UPDATE table
SET STATUS = #STATUS,
DATE_CREATED = COALESCE(#DATE_CREATED, GETDATE())
FROM table
From that point the column DATE_CLOSED is NULL. I wanted to automatically fill the column with the date of DATE_CREATED column but with the time of 10pm, and it should be filled by 10pm automatically and also the status filled to 'closed'.
You can calculate 10 p.m. on the current date using:
dateadd(hour, 22, cast(cast(getdate() as date) as datetime))
This is easy to add into the update. I'm not 100% sure, though, that this is all you are asking for.
If you are looking to schedule a query or stored procedure to run at a set time of the day, then the normal approach is to use SQL Server Agent which has fairly elaborate job scheduling functionality.
Look at this question for an example of how to run a daily job.
how to schedule a job for sql query to run daily?
And here's Microsoft's documentation: https://learn.microsoft.com/en-us/sql/ssms/agent/schedule-a-job

SQL Update Stored Procedure involving Subqueries

I have a few table's in my DB.
I am trying to update the rota table using a SQL stored procedure. I want the user to be able to type in, for example;
Name: Adam Brookes
Shift: Middle Day
On Call: Secondary
and using a subquery have it look up the id's of those and place them into the rota table. At the moment I am testing in Postman where I can define the 'date' and 'datekey' manually.
My Stored Procedure currently looks like this;
ALTER PROCEDURE [dbo].[RotaUpdateItems]
#date_key int,
#date date,
#user_id varchar(max),
#shift_type_id int,
#type_call_id int
AS
BEGIN
SET NOCOUNT ON;
UPDATE rota
SET date = #date,
user_id = (
SELECT user_id
FROM staff s
WHERE s.first_name LIKE 'ABC%'
),
shift_type_id = (
SELECT shift_type_id
FROM shifts h
WHERE h.shift_type LIKE 'ABC%'
),
type_call_id = (
SELECT type_call_id
FROM on_call c
WHERE c.type_of_call LIKE 'ABC%')
WHERE date_key = #date_key
END
I have referenced this question to get the LIKE 'ABC%' code to see if that would help convert "Primary" into '1', but this did not fully answer my question
I also researched this answer from John to see if a join is necessary when running an update query but this did not fully answer my question.

Update Trigger Query

I am using SQL Server 2014 with a table named dbo.ClientRecords. In this table I have a DateOfBirth field set as DATETIME and an Age field set as Nvarchar(40) at the moment. I know that this needs to be changed to int and I will do this.
I have the following query that essentially does a calculation based on the DateOfBirth field and the current date to work out the Age of the person. This works as I require it to.
SELECT id, DateOfBirth,
GETDATE() As [Today],
DATEDIFF (YY,DateOfBirth,GETDATE()) -
CASE
WHEN DATEADD(YY,DATEDIFF(YY,DateOfBirth,GETDATE()),DateOfBirth)
> GETDATE() THEN 1
ELSE 0
END AS [Age]
FROM dbo.ClientRecords
I am following the below website to create an update trigger as I need this update the age field once the insert statement for the web form has been submitted.
Tutorial about Triggers
This is my trigger that im trying to create, but I just cant seem to get this working.
CREATE TRIGGER [dbo].[Age_INSERT]
ON [dbo].[ClientRecords]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #id DATETIME
DECLARE #Age Varchar(40)
SELECT id,DateOfBirth,
GETDATE() As [Today],
DATEDIFF (YY,DateOfBirth,GETDATE()) -
CASE
WHEN DATEADD(YY,DATEDIFF(YY,DateOfBirth,GETDATE()),DateOfBirth)
> GETDATE() THEN 1
ELSE 0
END AS [Age]
FROM dbo.ClientRecords
INSERT INTO ClientRecords
VALUES(#id, #Age)
END
The error message that I get is the following.
Msg 213, Level 16, State 1, Procedure Age_INSERT, Line 21
Column name or number of supplied values does not match table definition.
I'm failing as im not to sure what I need to set as a variable. I thought that I would need the id from the ClientRecords table and the Age field.

Query to Stored Procedure in SSRS

I am getting data from a table and I am writing off to the report through a stored procedure. In the reporting part it has to show the results by users defined date.
E.g:
Today - should show today's results only
Yesterday - should show Yesterday's results only
How should I declare the values in a stored procedure and how can I implement in ssrs reporting part?
My CreateDate column keeps changing has the table (FailedJobsInfo) gets updated.
Here is my stored procedure:
ALTER PROCEDURE [dbo].[FailedJobsInfo]
#StartDate DATETIME
AS
SELECT
[SQLServer]
,[JobName]
,[StepName]
,[FailureMessage]
,[RunDateTime]
,[RunDuration]
,[CreateDate]
FROM
[dbo].[FailedJobsInfo]
WHERE
CONVERT(varchar(20), CreateDate, 101) = CONVERT(varchar(20), GETDATE(), 101)
Starting from your SSRS Report.
1) Create a Parameter with Labels and Values as below
Label Value
Today 0
Yesterday 1
2) Make your Procedure to accept an INT Parameter, If user selects Today it will pass zero 0 to stored procedure, if user selects Yesterday it will pass procedure 1 to procedure and this Integer value will be subtracted from your getdate() value avoiding time part. you will need to do as follow :
ALTER PROCEDURE [dbo].[FailedJobsInfo]
#StartPeriod INT
AS
BEGIN
SET NOCOUNT ON;
SELECT
[SQLServer]
,[JobName]
,[StepName]
,[FailureMessage]
,[RunDateTime]
,[RunDuration]
,[CreateDate]
FROM
[dbo].[FailedJobsInfo]
WHERE
CAST(CreateDate AS DATE) = CAST(GETDATE() AS DATE) - #StartPeriod --<--
END

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.
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.
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. I get an error that says "The Compound statement SQL construct or statement is not supported." 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. What is the best way to acclompish this?
And my second part of this question is in my WHERE statements. Is there a function to get today's date in the clockDate column rather than have to populate today's date? 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."
I hope I have explained this properly, and thank you for your help!!
EDIT:
#RThomas
#w00te
OK, so with the clockDate as a date field and breakOut as a time(0) field, should this work? Cause I'm still getting a "The Compound statement SQL construct or statement is not supported." 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? 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:
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. 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.
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. However, in some cases, especially with large data sets, the merge statement can be prohibitively slow, causing a lot of tran log activity. 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. I bet you'll like it.
Important note
Your code has a typo in your if statement in not exists(select...) part. Inner select statement has only one where condition while UserName condition is excluded from the not exists due to invalid brace completion. 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.
Let's continue to my answer...
SQL Server 2008+ support MERGE statement
MERGE statement is a beautiful TSQL gem very well suited for "insert or update" situations. 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. I think CONVERT(varchar(8), GETDATE(), 112) would give you just the date (not time) portion.
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 :)
You need to replace it as WHERE clockDate = { fn CURRENT_DATE() } AND userName = 'test'.
Please remove extra ")" from { fn CURRENT_DATE() })