SQL Converting int to varchar - sql

I need help converting an integer to a varchar.
I'm trying to write a procedure that takes in a ProfileID and a Currenttime; using those two values it finds the start time of the profileID and subtracts currenttime from
starttime and returns hours:minutes:seconds.
What am I doing wrong, is there a better way to write this?
Thanks.
CREATE PROCEDURE [dbo].[CalculateElaspedTime]
-- Add the parameters for the stored procedure here
#ProfileID nvarchar(10),
#CurrentDateTime datetime = ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
if #CurrentDateTime = CAST('' as datetime)
set #CurrentDateTime = GETDATE()
DECLARE #StartTime datetime;
DECLARE #ElaspedTime time;
DECLARE #hh int;
DECLARE #mm int;
DECLARE #ss int;
Declare #TimeString varchar
set #StartTime = (Select top 1 [DateTime] From Log WHERE ProfileID = #ProfileID);
set #hh = DateDiff(hour,#StartTime,#CurrentDateTime);
set #mm = DateDiff(minute,#StartTime,#CurrentDateTime)-60*#hh;
set #ss = DateDiff(second,#StartTime,#CurrentDateTime)-60*#mm;
set #TimeString = (Select CAST(#hh as varchar)); -- Fails Here
set #ElaspedTime = convert(datetime, cast(#hh as varchar) + ':' + cast(#mm as varchar) + ':' + cast(#ss as varchar));
INSERT INTO Log (ElaspedTime) Values (#ElaspedTime);
END

Try this. All of that excitement in the function may be unnecessary.
CONVERT(varchar(10),(#CurrentDateTime-#Start_Time),108)

One problem you have is this statement:
set #StartTime = (Select top 1 [DateTime] From Log WHERE ProfileID = #ProfileID);
Its results are indeterminate as SQL makes no guarantees about result order unless you explicitly specify it in an ORDER BY clause. You should be using ORDER BY or using an aggregate function like MAX() to get the row you want.
And you're doing a lot more work than necessary. SQL Server (recent versions, anyway) support date arithmetic, with the result of subtracting two dates being another date (offset from the SQL Server epoch of 1 Jan 1900 00:00:00.000. This simpler form ought to do you, unless the elapsed time will exceed 1 day:
create procedure dbo.CalculateElaspedTime
#ProfileID nvarchar(10) ,
#CurrentDateTime datetime = ''
as
set nocount on
declare
#now dateTime ,
#start datetime ,
#elapsed varchar(32)
select #now = case coalesce(#currentDateTime,'') when '' then current_timestamp else #currentDateTime end ,
#start = max( [DateTime] )
from dbo.Log
where ProfileId = #profileId
set #elapsed = convert(varchar,#now-#start,108)
insert dbo.Log ( ElapsedTime ) Values (#elapsed);
return 0
go
If your elapsed time might exceed one day, then your original approach is what you want:
create procedure dbo.CalculateElaspedTime
#ProfileID nvarchar(10) ,
#CurrentDateTime datetime = ''
as
set nocount on
declare #now dateTime = case coalesce(#currentDateTime,'') when '' then current_timestamp else #currentDateTime end ,
declare #start datetime = ( select max([DateTime]) from dbo.Log where profileId = #profileId )
declare #elapsed int = select datediff(ss,#now,#start)
declare
#hh int ,
#mm int ,
#ss int
set #hh = #elapsed / 3600 -- 3600 is seconds/hour
set #elapsed = #elapsed % 3600
set #mm = #elapsed / 60 -- 60 is seconds/minute
set #elapsed = #elapsed % 60
set #ss = #elapsed / 1 -- 1 is seconds/second :)
declare #hhmmss = right('00'+convert(varchar,#hh),2)
+ ':' + right('00'+convert(varchar,#mm),2)
+ ':' + right('00'+convert(varchar,#ss),2)
insert dbo.Log ( ElapsedTime ) Values (#hhmmss);
return 0
go

Related

Tuning a SQL server query by creating a new table however executing it takes a lot of time

Trying to run this query in SQL server but ran into problem, it takes a lot of time to get executed, I want to know is it the correct way to create a table there are many records and it stops working so basically I want to create a table with index and insert these record into the new table and set the job to read the record from that table.
This is the old query that takes a lot of time time to be executed
Update UsedTrs set Deleted=b.Deleted from
UsedTrs a inner join UsedTrs_Live b
on(a.ItemID=b.ItemID)
where (a.ArabicDate=b.ArabicDate collate Arabic_CI_AS) and (a.Deleted!=b.Deleted) and
(a.Code=b.Code) and (a.ItemType=b.ItemType) and
(a.ArabicDate>dbo.WesternToArabic(GETDATE()-90))
This is the new way that I have tried to insert it into a new table, but that takes a lot of time as well, my colleague said that collate Arabic_CI_AS will decrease the performance in the join which is on my first code, so I have tried this way to insert everything in a new table table and put indexes on the table and then grab the information through out the new table
here is the query for the new table but that takes a lot of time i am not sure if i am doing it correctly
select [id]
,[CreateDate]
,[TrsUserID]
,[UsedAmount]
,[ItemID]
,[ItemType]
,[Code]
,[Deleted]
,[ArabicDate]collate Arabic_CI_AS as [ArabicDate]
,[CostTypeFlag]
Into UsedTrs_Live_use_for_sp_TrsAmounts
From TrsUsed_Live
Where ArabicDate> dbo.WesternToArabic(GETDATE()-5)
update: it is now an hour already to run the query and it still executing and doesn't show any sign of completing, normally it should be faster, i don't know if that is the correct way
here is WesternToArabic function
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[WesternToArabic](#indate
DATETIME) RETURNS CHAR(10)
AS
BEGIN
DECLARE
#OutDate CHAR(10),
#DD NUMERIC,
#S INT,
#M INT,
#R INT,
#TMP VARCHAR(10),
#tmp1 NUMERIC,
#tmp2 NUMERIC
SET #tmp1 = CONVERT(NUMERIC, DATEADD(yy, 200, DATEADD(hh, -12,
#indate)))
SET #tmp2 = CONVERT(NUMERIC, CAST('18360320' AS DATETIME))
SET #DD = #tmp1- #tmp2
SET #S = ( FLOOR(#DD/46751)) * 128 + 1015
SET #DD = #Dd - FLOOR(#DD/ 46751) * 46751
SET #S = ( FLOOR(#DD/12053)) * 33 + #S
SET #DD = #DD - FLOOR(#Dd/12053) * 12053
IF #DD > 1826
BEGIN
SET #DD = #DD - 1826
SET #S = #S + 5 + FLOOR(#DD /1461) * 4
SET #DD = #Dd - FLOOR(#Dd/1461) * 1461
END
IF #DD > 365
BEGIN
SET #DD = #DD - 1
SET #S = #S + FLOOR(#DD / 365)
SET #DD = #Dd - FLOOR(#DD/365) * 365
END
IF #DD > 185
BEGIN
SET #DD = #DD - 186
SET #R = #Dd - FLOOR(#DD/30) * 30 + 1
SET #M = FLOOR(#DD/30) + 7
END
ELSE
BEGIN
SET #R = #Dd - FLOOR(#DD/31) * 31 + 1
SET #M = FLOOR(#DD/31) + 1;
END
IF #M < 10
SET #tmp = CAST(#S AS CHAR(4)) + '/0' + CAST(#M AS CHAR(1))
ELSE
SET #tmp = CAST(#S AS CHAR(4)) + '/' + CAST(#M AS CHAR(2))
IF #R < 10
SET #outdate = #tmp + '/0' + CAST(#R AS CHAR(1))
ELSE
SET #outdate = #tmp + '/' + CAST(#R AS CHAR(2))
RETURN(#OutDate)
END

Variable is declared but error messages says not

In the stored procedure shown below, I get this error, but I am declaring the #Remarks, so I cannot see what is the issue:
Msg 137, Level 15, State 2, Procedure sp_Insert_EMR_PATIENT_CHECK_TRACKING, Line 53
Must declare the scalar variable "#REMARKS".
Code:
create PROCEDURE [dbo].[sp_Insert_EMR_PATIENT_CHECK_TRACKING]
#HOUR int,
#TIME int,
#MRN nchar(10),
#NURSING_UNIT varchar(12),
#CHECK_DATE datetime,
#MONITOR_CODE nchar(10),
#Remarks nvarchar(500),
#Pain_Level int
AS
BEGIN
SET NOCOUNT ON;
If #Remarks = 'undefined'
BEGIN
SET #Remarks = null
END
IF NOT EXISTS (SELECT *
FROM [OGEN].[EMR_PATIENT_CHECK_TRACKING]
WHERE CHECK_DATE = #CHECK_DATE
AND MRN = #MRN
AND NURSING_UNIT = #NURSING_UNIT
AND HOUR = #HOUR
AND TIME = #TIME
AND MONITOR_CODE = #MONITOR_CODE)
BEGIN
INSERT INTO [OGEN].[EMR_PATIENT_CHECK_TRACKING] ([CHECK_DATE], [MRN], [NURSING_UNIT], [HOUR], [TIME], [MONITOR_CODE], [Pain_Level])
VALUES (#CHECK_DATE, #MRN, #NURSING_UNIT, #HOUR, #TIME, #MONITOR_CODE, #Pain_Level)
IF NOT EXISTS (SELECT *
FROM [OGEN].[EMR_PATIENT_CHECK_TRACKING_REMARK]
WHERE CHECK_DATE = #CHECK_DATE
AND MRN = #MRN
AND NURSING_UNIT = #NURSING_UNIT
AND HOUR = #HOUR
AND MONITOR_CODE = #MONITOR_CODE)
BEGIN
INSERT INTO [OGEN].[EMR_PATIENT_CHECK_TRACKING_REMARK] ([CHECK_DATE], [MRN], [NURSING_UNIT], [HOUR], [MONITOR_CODE], [REMARKS])
VALUES (#CHECK_DATE, #MRN, #NURSING_UNIT, #HOUR, #MONITOR_CODE, ISNULL(#REMARKS,''))
END
ELSE
BEGIN
UPDATE [OGEN].[EMR_PATIENT_CHECK_TRACKING_REMARK]
SET REMARKS = ISNULL(#Remarks,REMARKS)
WHERE CHECK_DATE = #CHECK_DATE
AND [MRN] = #MRN
AND [NURSING_UNIT] = #NURSING_UNIT
AND [HOUR] = #HOUR
AND [MONITOR_CODE] = #MONITOR_CODE
END
END
ELSE
BEGIN
UPDATE [OGEN].[EMR_PATIENT_CHECK_TRACKING]
SET [Pain_Level]=#Pain_Level
WHERE CHECK_DATE = #CHECK_DATE
AND MRN = #MRN
AND NURSING_UNIT = #NURSING_UNIT
AND HOUR = #HOUR
AND TIME = #TIME
AND MONITOR_CODE = #MONITOR_CODE
UPDATE [OGEN].[EMR_PATIENT_CHECK_TRACKING_REMARK]
SET REMARKS = Isnull(#Remarks,REMARKS)
WHERE CHECK_DATE = #CHECK_DATE
AND [MRN] = #MRN
AND [NURSING_UNIT] = #NURSING_UNIT
AND [HOUR] = #HOUR
AND [MONITOR_CODE] = #MONITOR_CODE
END
END
The parameter #Remarks is declared using camel case and later in your stored procedure you reference it as #REMARKS - it could be that you are using a case-sensitive collation and this will result in the error you are seeing.
If your database collation contains "_CI" (e.g. Latin1_General_CI_AS) then it is case-insensitive, if it contains "_CS" it is a case-sensitive collation.
Based on the error information, your server is set to be case-sensitive. This can be confirmed via,
SELECT CONVERT (varchar, SERVERPROPERTY('collation'));
Running the above statement on my case-sensitive server returns, SQL_Latin1_General_CP1_CS_AS.
To bypass that error, you must rename #REMARKS to #Remarks which you had defined or append a COLLATE statement to change the sensitivity to be case-insensitive. On my server, this would be SQL_Latin1_General_CP1_CI_AS.
The better choice would be to remain consistent with your variable naming convention.
On the same case-sensitive server,
DECLARE #value VARCHAR(10) = 'hello'
SELECT #VALUE <<< ERROR.
SELECT #value COLLATE SQL_Latin1_General_CP1_CI_AS <<< returns, 'hello'

Can't understand why i'm getting an incorrect syntax error in my script?

Can anyone tell me why I'm getting an incorrect syntax error for the line
SELECT * INTO #pre_and_post_op FROM NBOCAP(#StartDate,#EndDate,#OrgCode)
Code:
DECLARE #StartDate datetime
DECLARE #EndDate datetime
DECLARE #OrgCodeString varchar (8000)
SET #StartDate = '01-JAN-11'
SET #EndDate = '31-MAR-14'
SET #OrgCodeString = 'RA720|RQ801|RVJ20|RN325|8AAAA|RBA11'
DECLARE #i int
DECLARE #OrgCode varchar(10)
DECLARE #OrgCount int
DECLARE #TrustTable TABLE
(idx int IDENTITY(1,1), org varchar(10))
DECLARE #pre_and_post_op TABLE
(CARE_ID int,ERR_NumberOfNodesPositive int,ERR_FinalPathologyTCategory int,
ERR_FinalPathologyNCategory int,ERR_FinalMCategory int)
INSERT INTO #TrustTable
SELECT * FROM SplitString(#OrgCodeString, '|')
SET #i = 1
SET #OrgCount = (SELECT COUNT(*) FROM #TrustTable)
IF #OrgCount > 0
WHILE (#i <= #OrgCount)
BEGIN
SET #OrgCode = (SELECT org FROM #TrustTable WHERE idx = #i)
SELECT * INTO #pre_and_post_op FROM NBOCAP(#StartDate,#EndDate,#OrgCode)
SET #i = #i + 1
END
You cannot SELECT INTO a table variable. To quote MSDN:
You cannot specify a table variable or table-valued parameter as the new table.
Use INSERT INTO ... SELECT instead
INSERT INTO #pre_and_post_op SELECT * FROM NBOCAP(#StartDate,#EndDate,#OrgCode)

How can i make the date dynamic in this query. where when i run the query it picks up the current date in the same format as it is in the query

I need to be able to run the query and it will do the same as the query below but it picks up the date without entering it. The date is in the query is because we ran it earlier at that date and time.
DECLARE #Results TABLE
(
_id binary(12),
TimeDetected datetimeoffset,
UserName nvarchar(max),
ValueOld nvarchar(max),
ValueNew nvarchar(max),
FS_FolderPath nvarchar(max),
FS_FileName nvarchar(max),
ResultID int,
EventID uniqueidentifier,
EventClassID uniqueidentifier,
FacilityID int,
ActionID int,
ValueTypeID int,
MissingOld bit,
MissingNew bit,
TimeZoneOffset int,
EventClassName nvarchar(max),
ActionName nvarchar(max)
)
SET NOCOUNT ON;
SET DATEFORMAT ymd;
DECLARE #dt datetimeoffset;
SET #dt='2014-02-07 13:00';
DECLARE #totalCount int = 0;
WHILE #totalCount < 50000
AND #dt >= '2013-02-07 13:00'
BEGIN
DECLARE #count int = 0;
DECLARE #tmp TABLE
(
_id binary(12)
);
WHILE #count < 50000
AND #dt >= '2013-02-07 13:00'
BEGIN
INSERT INTO #tmp
SELECT *
FROM (SELECT _id
FROM AuditEvent_IX_SubsystemID WITH(NOLOCK)
WHERE _date_hh = #dt
AND SubsystemID IN ( 3 )) AS I;
SET #count = #count + ##ROWCOUNT;
SET #dt = DATEADD(hh, -1, #dt);
END;
INSERT INTO #Results
(TimeDetected,
UserName,
ValueOld,
ValueNew,
FS_FolderPath,
FS_FileName,
ResultID,
EventID,
EventClassID,
FacilityID,
ActionID,
ValueTypeID,
MissingOld,
MissingNew,
TimeZoneOffset,
_id,
EventClassName,
ActionName)
SELECT TOP 50000 AET.TimeDetected,
AET.UserName,
AET.ValueOld,
AET.ValueNew,
AET.FS_FolderPath,
AET.FS_FileName,
AET.ResultID,
AET.EventID,
AET.EventClassID,
AET.FacilityID,
AET.ActionID,
AET.ValueTypeID,
AET.MissingOld,
AET.MissingNew,
AET.TimeZoneOffset,
AET._id,
EC.EventClassName,
AN.ActionName
FROM dbo.AuditEvent AS AET WITH(NOLOCK)
JOIN #tmp AS tmp
ON AET._id = tmp._id
LEFT OUTER JOIN Event.Class AS EC
ON AET.EventClassID = EC.EventClassID
LEFT OUTER JOIN Event.Action AS AN
ON AET.ActionID = AN.ActionID
WHERE ( TimeDetected BETWEEN '2013-02-07 13:53:58.134' AND '2014-02-07 13:53:58.134' )
AND (( AET.SubsystemID = 3
AND AET.FS_FolderPath = N'E:\Lanfax\Inbox\'
AND ( AET.ActionID & 32 ) != 0 ))
SET #totalCount = #totalCount + ##ROWCOUNT;
DELETE FROM #tmp;
END
SELECT TOP 50000 *
FROM #Results
Try this for setting the hour:
set #dt = dateadd(hour, 13, cast(cast(getdate() as date) as datetimeoffset))
To subtract a year:
set #dt = dateadd(hour, 13, cast(cast(dateadd(year, -1, getdate()) as date) as datetimeoffset))
I'm not entirely sure I understood the question. However, if you want #dt to automatically be set to the datetime at which the query is run so that you do not enter it manually; I recommend using the getdate function.
DECLARE #dt datetimeoffset;
SET #dt=GETDATE()
I hope this is helpful.

How to recursively update a table with a stored procedure

I have a stored procedure that selects some data in a different format from my original table:
USE [VolTracker]
GO
DECLARE #return_value int,
#offset int
SET #offset = 5
WHILE #offset >= 1 BEGIN
EXEC #return_value = [dbo].[sp_getStats]
#Doffset = #offset,
#StartTime = --Some Datetime,
#EndTime = --Some later Datetime,
#Contract = NULL
SET #offset = #offset - 1
END
GO
This specific example selects all 5 of the tables that I would like it to properly. However, I would like all of these tables joined into one table. How might I go about doing this?
Create a table variable that matches the schema of the resultset returned by sp_getStats. Then, insert into this variable within your loop:
...
declare #Stage table (YourColumn1 varchar(10), YourColumn2 int, ...);
WHILE #offset >= 1 BEGIN
INSERT INTO #Stage
EXEC #return_value = [dbo].[sp_getStats]
#Doffset = #offset,
#StartTime = --Some Datetime,
#EndTime = --Some later Datetime,
#Contract = NULL
SET #offset = #offset - 1
END
select * from #Stage;
The above will work to return the union of all the resultsets returned, however if its possible for you to modify the procedure (or create a new one) that can return the complete set without a loop then I would suggest doing do.
Create a temporary table or table variable and insert into table each time you execute the stored procedure. Check this out.
//declare your #temptable here
WHILE #offset >= 1 BEGIN
INSERT INTO #tempTable
EXEC #return_value = [dbo].[sp_getStats]
#Doffset = #offset,
#StartTime = --Some Datetime,
#EndTime = --Some later Datetime,
#Contract = NULL
SET #offset = #offset - 1
END