How do check if a time is greater than a particular one? - sql

I am building a windows form application and for my database I want to create a procedure to insert values. For this procedure I want to check if the time is later than 8:45 then you are considered late.
Here is what I was trying so far
Create Procedure "Insert Attendance"
(
#att_id int,
#emp_id integer,
#work_date date,
#expected_time time(7)
#time_in time(7),
#time_out time(7),
#time_elapse time(7),
#time_status varchar(20)
)
As
Begin
If ((time_in=#time_in)>16:45)
then set time_status = 'Late'
Begin
Insert Into attendance
Values
(#att_id,#emp_id,#work_date,#expected_time,#time_in,#time_out,#time_elapse,#time_status)
End
Else
Begin
Select 'Error'
End
End

You can use string constants to define the time to compare to:
...
IF #time_in > '08:45'
BEGIN
SET time_status = 'Late';
...
Also note, that in SQL Server there is no THEN for IF.

Related

Stored procedure : Select data from Table "A" and insert data on Table "B"

I haven't touched stored procedures and functions for a very long time.
So I decided to make a mini-training database for myself.
At the moment, I'm trying to create a procedure that comes in and selects data from one table (Test_trigger) and says that if the sum for a colour exceeds a threshold, then I write an alert row to another table (Test_alm_trigger)
Here are my 2 tables creation script :
create table Test_trigger (
id INT IDENTITY(1,1) PRIMARY KEY,
Couleur VARCHAR(50),
Horodate DATETIME,
Nombre DECIMAL(6,2),
Seuil_fixe INT
);
create table Test_alm_trigger (
id_alm INT IDENTITY(1,1) PRIMARY KEY,
Label VARCHAR(100),
Horodate DATETIME,
Seuil DECIMAL(6,2)
);
To be more precise, the goal is :
when a colour ([Couleur]), such as "Blue", has a sum of the [Nombre] column above the threshold entered ([Seuil_fixe]), then the procedure runs and inserts a row in the Test_alm_trigger table with a [Label], the date the addition was made ( SYSDATETIME() ) and the sum of the [Nombre] column.
I have created this procedure but I am not sure how it works or if it is good or not
CREATE PROCEDURE ajoutL_triggerAlm
(
#Couleur nvarchar(50),
#Label nvarchar(200) = 'Dépassement de seuil',
#Seuil float(4),
#Seuil_fixe float(4),
#Msg nvarchar(200)
)
AS
BEGIN
IF EXISTS (
SELECT [Couleur]
FROM Test_trigger
GROUP BY [Couleur], [Nombre], [Seuil_fixe]
HAVING [Couleur] = #Couleur AND
SUM([Nombre]) = #Seuil AND
[Seuil_fixe] = #Seuil_fixe AND
#Seuil > #Seuil_fixe
)
BEGIN
SET #Msg = 'Debug'
END
ELSE
BEGIN
INSERT INTO Test_alm_trigger
VALUES (#Label, SYSDATETIME(), #Seuil)
END
END
If you have any answers, tips... I'll take them.
Thank you in advance
The main change I would suggest is making your procedure set-based rather than procedural. Relational databases are optimised for set-based operations so you should try and get into the mindset of operating that way yourself.
I've added other best practices.
CREATE PROCEDURE ajoutL_triggerAlm
(
#Couleur nvarchar(50)
, #Label nvarchar(200) = 'Dépassement de seuil'
-- Almost never use float, its not a precise numeric amount and should only be used when specifically required
, #Seuil decimal(8,4)
-- Almost never use float, its not a precise numeric amount and should only be used when specifically required
, #Seuil_fixe decimal(8,4)
, #Msg nvarchar(200)
)
AS
BEGIN
-- Best practice (I'll leave the meaning as an exercise)
-- SQL Server recommendation is to ";" terminate all statements
SET NOCOUNT, XACT_ABORT ON;
-- Best practice, always list the columns you are inserting into
-- Use set-based operations instead of procedural where you can
INSERT INTO dbo.Test_alm_trigger (Label, Horodate, Seuil)
SELECT #Label, SYSDATETIME(), #Seuil
-- Question states when SUM([Nombre] above the threshold #Seuil_fixe - so I think this is the logic
-- Although its not clear where the column Seuil_fixe comes into it
WHERE (
SELECT SUM([Nombre])
FROM Test_trigger
WHERE [Couleur] = #Couleur
) > #Seuil_fixe;
-- Detect failure using ##ROWCOUNT
SET #Msg = CASE WHEN ##ROWCOUNT = 0 THEN 'Debug' ELSE NULL END;
-- Return a status, can use other values to indicate errors
RETURN 0;
END;

Stored Procedure Output Value Not Updating

Everyone.
I have created a stored procedure in SQL Server 2016 that has the purpose of giving the of the total number of sales recommendations [#Recommendation in Recommendations table] in my table that contain this string: '____Document DOB in sales record' past any given date. I want to put this result into a temporary table as well.
Helpful Table Info:
Reference Table where I am grabbing the data: Recommendations
The relevant fields in the Recommendations table are #Recommendation, and #SalesProcessTime
The #Recommendation field is a VARCHAR(255), and #SalesProcessTime is a DATETIME
Regardless of what I change the date to - or even if I make it =, >=, etc - the same numeric value is displayed.
If you need anything else, please don't hesitate to ask me.
USE [Test_Database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE usp_SalesRefCount
AS
BEGIN
--IF OBJECT_ID('tempdb..DocDOB') IS NOT NULL DROP TABLE #DocDOB
DECLARE #NumRecs INT;
-- Count of the number of recommendations
SELECT #NumRecs = COUNT(Recommendation)
FROM [Master_AGGREGATE].[dbo].[Recommendations]​
WHERE Recommendation = '____Document DOB in pt record' ​
and SalesProcessTime > '2018-10-20'
CREATE TABLE ##RefCount (NumberOfRecs INT);
INSERT INTO ##RefCount
SELECT #NumRecs
END
EXEC usp_SalesRefCount
SELECT * FROM ##DocDOB
Why are you using a global temporary table at all? Why not just return the results from the procedure directly? eg:
CREATE PROCEDURE usp_SalesRefCount
AS
BEGIN
DECLARE #NumRecs INT;
SELECT #NumRecs = COUNT(Recommendation)
FROM [Master_AGGREGATE].[dbo].[Recommendations]​
WHERE Recommendation = '____Document DOB in pt record' ​
and SalesProcessTime > '2018-10-20'
SELECT #NumRecs NumRecs
END
You are inserting data into a global temporary table "##RefCount" and selecting from another one "##DocDOB", so the result will never change.
Anyway, as #DavidBrowne said, you should just return the result directly
CREATE PROCEDURE usp_SalesRefCount
AS
BEGIN
SELECT COUNT(Recommendation)
FROM [Master_AGGREGATE].[dbo].[Recommendations]​
WHERE Recommendation = '____Document DOB in pt record' ​
and SalesProcessTime > '2018-10-20'
END
Also, another idea, maybe get that date as a parameter, so you don't have to update the stored procedure when you need to select by another date
CREATE PROCEDURE usp_SalesRefCount
#selectDate DateTime
AS
BEGIN
SELECT COUNT(Recommendation)
FROM [Master_AGGREGATE].[dbo].[Recommendations]​
WHERE Recommendation = '____Document DOB in pt record' ​
and SalesProcessTime > #selectDate
END

Generate a unique column sequence value based on a query handling concurrency

I have a requirement to automatically generate a column's value based on another query's result. Because this column value must be unique, I need to take into consideration concurrent requests. This query needs to generate a unique value for a support ticket generator.
The template for the unique value is CustomerName-Month-Year-SupportTicketForThisMonthCount.
So the script should automatically generate:
AcmeCo-10-2019-1
AcmeCo-10-2019-2
AcmeCo-10-2019-3
and so on as support tickets are created. How can ensure that AcmeCo-10-2019-1 is not generated twice if two support tickets are created at the same time for AcmeCo?
insert into SupportTickets (name)
select concat_ws('-', #CustomerName, #Month, #Year, COUNT())
from SupportTickets
where customerName = #CustomerName
and CreatedDate between #MonthStart and #MonthEnd;
One possibility:
Create a counter table:
create table Counter (
Id int identify(1,1),
Name varchar(64)
Count1 int
)
Name is a unique identifier for the sequence, and in your case name would be CustomerName-Month-Year i.e. you would end up with a row in this table for every Customer/Year/Month combination.
Then write a stored procedure similar to the following to allocate a new sequence number:
create procedure [dbo].[Counter_Next]
(
#Name varchar(64)
, #Value int out -- Value to be used
)
as
begin
set nocount, xact_abort on;
declare #Temp int;
begin tran;
-- Ensure we have an exclusive lock before changing variables
select top 1 1 from dbo.Counter with (tablockx);
set #Value = null; -- if a value is passed in it stuffs us up, so null it
-- Attempt an update and assignment in a single statement
update dbo.[Counter] set
#Value = Count1 = Count1 + 1
where [Name] = #Name;
if ##rowcount = 0 begin
set #Value = 10001; -- Some starting value
-- Create a new record if none exists
insert into dbo.[Counter] ([Name], Count1)
select #Name, #Value;
end;
commit tran;
return 0;
end;
You could look into using a TIME type instead of COUNT() to create unique values. That way it is much less likely to have duplicates. Hope that helps

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.

sql stored procedure not working(no rows affected)

trying to get this stored procedure to work.
ALTER PROCEDURE [team1].[add_testimonial]
-- Add the parameters for the stored procedure here
#currentTestimonialDate char(10),#currentTestimonialContent varchar(512),#currentTestimonialOriginator varchar(20)
AS
BEGIN
DECLARE
#keyValue int
SET NOCOUNT ON;
--Get the Highest Key Value
SELECT #keyValue=max(TestimonialKey)
FROM Testimonial
--Update the Key by 1
SET #keyValue=#keyValue+1
--Store into table
INSERT INTO Testimonial VALUES (#keyValue, #currentTestimonialDate, #currentTestimonialContent, #currentTestimonialOriginator)
END
yet it just returns
Running [team1].[add_testimonial] ( #currentTestimonialDate = 11/11/10, #currentTestimonialContent = this is a test, #currentTestimonialOriginator = theman ).
No rows affected.
(0 row(s) returned)
#RETURN_VALUE = 0
Finished running [team1].[add_testimonial].
and nothing is added to the database, what might be the problem?
There may have problems in two place:
a. There is no data in the table so, max(TestimonialKey) returns null, below is the appropriate way to handle it.
--Get the Highest Key Value
SELECT #keyValue= ISNULL(MAX(TestimonialKey), 0)
FROM Testimonial
--Update the Key by 1
SET #keyValue=#keyValue+1
b. Check your data type of the column currentTestimonialDate whether it is char or DateTime type, if this field is datetime type in the table then convert #currentTestimonialDate to DateTime before inserting to the table.
Also, check number of columns that are not null allowed and you're passing data to them.
If you're not passing data for all columns then try by specifying columns name as below:
--Store into table
INSERT INTO Testimonial(keyValue, currentTestimonialDate,
currentTestimonialContent, currentTestimonialOriginator)
VALUES (#keyValue, #currentTestimonialDate,
#currentTestimonialContent, #currentTestimonialOriginator)
EDIT:
After getting the comment from marc_s:
Make keyValue as INT IDENTITY, If multiple user call it concurrently that wont be problem, DBMS will handle it, so the ultimate query in procedure might be as below:
ALTER PROCEDURE [team1].[add_testimonial]
-- Add the parameters for the stored procedure here
#currentTestimonialDate char(10),
#currentTestimonialContent varchar(512),#currentTestimonialOriginator varchar(20)
AS
BEGIN
SET NOCOUNT ON;
--Store into table
INSERT INTO Testimonial VALUES (#currentTestimonialDate,
#currentTestimonialContent, #currentTestimonialOriginator)
END
Two issues that I can spot:
SELECT #keyValue=max(TestimonialKey)
should be
SELECT #keyValue=ISNULL(max(TestimonialKey), 0)
To account for the case when there are no records in the database
Second, I believe that with NOCOUNT ON, you will not return the count of inserted rows to the caller. So, before your INSERT statement, add
SET NOCOUNT OFF