Update data based on other column - sql

I have a table and want to update a column based on other column of same table. Please look at below image for table design and table data.
In this tbl I want to update JoinDate as below steps.
1) if ModifiedDatetime is not null then ModifiedDatetime else CreatedDate.
2) Now if NextLevel is Hour then want to add hour of above date which we have in setp 1
3) Now if NextLevel is Day then want to add Day of above date which we have in setp 1
4) Now if NextLevel is Min then want to add Min of above date which we have in setp 1
5) Finally after completing all above process the date which I will get , I want to use to that data to update joindate.
I did this usig below cursor but I wnat to do this using sql update query.
DECLARE #EmpID INT
Declare #DtTm datetime
DECLARE #NextLevl INT
Declare #JoinDtTm datetime
DECLARE CurProg CURSOR FOR
select EmpID from tblEmp
OPEN CurProg
FETCH NEXT
FROM CurProg INTO #EmpID
WHILE ##FETCH_STATUS = 0
BEGIN
select #DtTm = case when ModifiedTime is null then CreatedDate else ModifiedTime end, #NextLevl = NextLevel from tblEmp where EmpID = #EmpID
if (#NextLevl = 'Min')
BEGIN
set #JoinDtTm = DATEADD(MI,1,#DtTm)
END
ELSE IF (#NextLevl= 'Hour')
BEGIN
set #JoinDtTm = DATEADD(HH,1,#DtTm)
END
ELSE
BEGIN
set #JoinDtTm = DATEADD(D,1,#DtTm)
END
--update tblEmp set JoinDtTm = #JoinDtTm where EMPId= #EMPId
FETCH NEXT
FROM CurProg INTO #EmpID
END
CLOSE CurProg
DEALLOCATE CurProg
Thanks,
Hitesh

Try this:
UPDATE TableName
SET JoinDate = CASE WHEN NextLevel = 'Hour' THEN DATEADD(HH,1,ISNULL(ModifiedDate,CreatedDate))
WHEN NextLevel = 'Day' THEN DATEADD(DD,1,ISNULL(ModifiedDate,CreatedDate))
WHEN NextLevel = 'Min' THEN DATEADD(MI,1,ISNULL(ModifiedDate,CreatedDate))
END

To do this without a cursor in an update statement then this should work
UPDATE TBL_EMP
SET JOINDATE =
(CASE WHEN MODIFIEDTIME IS NOT NULL
THEN (CASE WHEN NEXTLEVEL ='Hour' THEN dateadd(hh,1,modifiedtime)
ELSE (CASE WHEN NEXTLEVEL = 'Day' THEN dateadd(dd,1,MODIFIEDTIME)
ELSE(CASE WHEN NEXTLEVEL = 'Min' THEN dateadd(n,1,MODIFIEDTIME) ELSE MODIFIEDTIME END) END) END)
ELSE(CASE WHEN NEXTLEVEL ='Hour' THEN dateadd(hh,1,CREATEDDATE)
ELSE(CASE WHEN NEXTLEVEL = 'Day' THEN dateadd(dd,1,CREATEDDATE)
ELSE(CASE WHEN NEXTLEVEL = 'Min' THEN dateadd(n,1,CREATEDDATE) ELSE CREATEDDATE END) END) END) END)
FROM TBL_EMP

Drop your column joindate, it is redundant. Since joindate always rely on other columns in the same row, all you need is a computed column like this, otherwise you are stuck on constantly maintaining the values in joindate:
ALTER TABLE YourTable
ADD cJoindate as
CASE NextLevel
WHEN 'day' THEN DATEADD(D, 1, COALESCE(ModifiedDate,CreatedDate))
WHEN 'min' THEN DATEADD(MI, 1, COALESCE(ModifiedDate,CreatedDate))
WHEN 'hour' THEN DATEADD(HH, 1, COALESCE(ModifiedDate,CreatedDate))
END

Related

How to avoid not to query tables or views in scalar functions?

I have scalar functions( 4 functions) in my View. It drastically reduces the view's performance. I believe the reason for that is I use SELECT queries in my scalar functions.
EG:
CREATE FUNCTION [dbo].[udf_BJs_GENERAL]
(
#TankSystemId int,
#TimeStamp datetime2(7)
)
RETURNS varchar(10)
AS
BEGIN
DECLARE #leakChk varchar(10);
DECLARE #allowableVariance float;
DECLARE #GallonsPumped int;
DECLARE #DailyOverOrShort float;
DECLARE #TimePeriod datetime2(7);
DECLARE #ReportDate datetime2(7)
SELECT TOP 1 #TimePeriod = Date
FROM [bjs].udv_DailySiraData
where TankSystemId=#TankSystemId ORDER BY Date DESC
SET #ReportDate=#TimePeriod
IF( #TimeStamp <= #TimePeriod)
SET #ReportDate=#TimeStamp
SELECT #GallonsPumped = SUM(GallonsPumped)
FROM [bjs].[udv_DailySiraData]
where TankSystemId=#TankSystemId
and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
SELECT #DailyOverOrShort = SUM(DailyVar)
FROM [bjs].[udv_DailySiraData]
where TankSystemId=#TankSystemId
and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
SELECT #allowableVariance= (#GallonsPumped/100) + 130
SET #leakChk='FAIL'
IF (#allowableVariance > ABS(#DailyOverOrShort))
SET #leakChk = 'PASS'
RETURN #leakChk;
How can i avoid such situations? Is there a way to do select queries in my View and pass that result to my scalar function?
Try this:
create function dbo.udf_BJs_GENERAL(
#TankSystemId int,
#TimeStamp datetime2(7)
) returns varchar(10) as
with dates as (
select top 1
ReportDate = case when #TimeStamp <= Date then #TimeStamp else Date
from bjs.udv_DailySiraData
where TankSystemId=#TankSystemId
order by Date desc
),
gallons as (
select
allowableVariance = ( sum(GallonsPumped)/100) + 130,
DailyOverOrShort = sum(DailyVar)
from bjs.udv_DailySiraData data
join dates
on data.Date <= dates.ReportDate
and date.Date >= dateadd(mm, datediffmm, 0, dates.ReportDate), 0)
where TankSystemId = #TankSystemId
)
select
leakChk = cast( case when allowableVariance > ABS(DailyOverOrShort))
then 'PASS' else 'FAIL' end as varchar(10) )
from gallons
your case is special, your have a special input parameter,assue the timestamp parameter is on Day level
This view will return check result of each TankSystemId on every day.
Then join will your query with TankSystemId and Day.
But if the input parameter is more detail. I think it is difficult to convert this function to view
CREATE view [dbo].[uvw_BJs_GENERAL]
AS
BEGIN
/*
SET #ReportDate=#TimePeriod
IF( #TimeStamp <= #TimePeriod)
SET #ReportDate=#TimeStamp
*/
SELECT TankSystemId,b.[Date]
,GallonsPumped = SUM(GallonsPumped),DailyOverOrShort = SUM(DailyVar)
,leakChk=CASE WHEN (SUM(GallonsPumped)/100) + 130)> ABS(SUM(DailyVar)) THEN 'PASS' ELSE 'FAIL' END
FROM [bjs].[udv_DailySiraData] AS a
INNER JOIN (
SELECT CONVERT(DATE,[Date]) AS [Date] FROM [bjs].[udv_DailySiraData] GROUP BY TankSystemId, CONVERT(DATE,[Date])
) b ON a.TankSystemId=b.TankSystemId AND DATEDIFF(d,a.[Date],b.[Date])>=0
-- and Date <=#ReportDate and Date >= DATEADD(mm, DATEDIFF(mm,0,#ReportDate), 0)
GROUP BY TankSystemId,b.[Date]
END

How to execute the query only when mainframe is up?

I have a query which has to be executed only when the mainframe is up. Mainframe is down during these hours
tuesday to saturday - 1am to 6am,
sunday - 1am - 12pm.
I am trying to declare a variable which gets the current date and time and then trying to write a logic in the if statement to satisfy the above condition.
if #new_que_stat_cd = 'U'
BEGIN
--declare #recv_time datetime = getdate()
--if CASE WHEN datepart(dw,#recv_time) in ('SUNDAY') AND
--,'TUESDAY','WEDNESDAY','
--declare #ident int = IDENT_CURRENT( 'SADEV.RO_Transcript.ETQueueCtrl' )
UPDATE NEW SET [ETQueueCtrlStatusCd] = 'U'
from sadev.RO_Transcript.ETQueueCtrl NEW
where new.[ETQueueCtrlStatusCd] = 'S'
AND new.ErrorFl = 'N'
and new.VendorTransactionID is not null
and new.VendorTransactionIDRcvdDate is not null
and new.ETQueueCtrlID = #queuectrl_id
select new.VendorTransactionIDRcvdDate
from sadev.RO_Transcript.ETQueueCtrl NEW
where new.[ETQueueCtrlStatusCd] = #new_que_stat_cd
AND new.ErrorFl = 'N'
and new.VendorTransactionID is not null
and new.ETQueueCtrlID = #queuectrl_id
END
WILL THIS LOGIC WORK FOR THE ABOVE CONDITION
declare #recv_time datetime = getdate()
if (convert(varchar,(datepart(DAY,#recv_time))) in ('SUNDAY')
AND convert(varchar, #recv_time, 114) between convert(datetime,'01:00') and convert(datetime,'12:00'))
or
convert(varchar,(datepart(DAY,#recv_time))) in ('Tuesday','Wednesday','Thursday','Friday','Saturday')
AND convert(varchar, #recv_time, 114) between convert(datetime,'01:00') and convert(datetime,'06:00')
Based on: DATEPART (Transact-SQL)
Try this:
IF #new_que_stat_cd = 'U'
BEGIN
DECLARE #currDate DATETIME=GETDATE();
DECLARE #runProcess BIT=0;
SELECT #runProcess=CASE
WHEN DATEPART(dw, #currDate) IN
(3, 4, 5, 6, 7
)
THEN CASE
WHEN DATEPART(hh, #currDate) BETWEEN 1 AND 6
THEN 1
ELSE 0
END
WHEN DATEPART(dw, #currDate) IN
(1
)
THEN CASE
WHEN DATEPART(hh, #currDate) BETWEEN 1 AND 12
THEN 1
ELSE 0
END
ELSE 0
END;
IF #runProcess = 1
BEGIN
UPDATE NEW
SET ETQueueCtrlStatusCd='U'
FROM sadev.RO_Transcript.ETQueueCtrl NEW
WHERE new.ETQueueCtrlStatusCd = 'S'
AND new.ErrorFl = 'N'
AND new.VendorTransactionID IS NOT NULL
AND new.VendorTransactionIDRcvdDate IS NOT NULL
AND new.ETQueueCtrlID = #queuectrl_id;
SELECT new.VendorTransactionIDRcvdDate
FROM sadev.RO_Transcript.ETQueueCtrl NEW
WHERE new.ETQueueCtrlStatusCd = #new_que_stat_cd
AND new.ErrorFl = 'N'
AND new.VendorTransactionID IS NOT NULL
AND new.ETQueueCtrlID = #queuectrl_id;
END;
END;
Where 3,4,5,6,7 are Tuesday to Saturday respectively and 1 is Sunday.

return data even if they are errors

I have a stored procedure, in which return a table containing date,presence,total working hour if present...
Total Working Hour is calculated in a separate function that return a decimal value, But sometimes employees have a mistakes in data, like a duplicate punches or punch (out or in) for twice,
if any of the above scenario exist the function returned an error, and therefore The SP return error...
My request is when any error is occurred, i want to return 0 or -1 or whatever instead of the error, to forces the SP to return data even if they are errors..
The Error generating every time is :
SQL Server Subquery returned more than 1 value.
This is not permitted when the subquery follows =, !=, <, <= , >, >=
So I want in every time when this error occurred, to return a value instead of it,
the SP Code is:
ALTER PROCEDURE [dbo].[SM_GetAttendance]
(
#StartDate date ,
#EndDate date ,
#EmployeeID NVARCHAR(6)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE dte_Cursor CURSOR FOR
WITH T(date)
AS
(
SELECT #StartDate
UNION ALL
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < #EndDate
)
SELECT date FROM T OPTION (MAXRECURSION 32767);
DECLARE #date NVARCHAR(20);
CREATE TABLE #datetable(date DATETIME,Status NVARCHAR(50),nbOfWorkingHour DECIMAL(36,2))
--SELECT date FROM T
set #date = ''
OPEN dte_Cursor
FETCH NEXT FROM dte_Cursor INTO #date
WHILE ##FETCH_STATUS = 0
BEGIN
insert #datetable
SELECT
cast((select distinct Convert(Nvarchar(12),date,102) from Attendance where date = #date
and employeeid =#EmployeeID ) as nvarchar(30))
date
,CASE WHEN EXISTS (select 1 from Attendance
where employeeid=#EmployeeID and date = #date)
then 'Present'
else 'absent'
end Status
,dbo.GetWorkingHourPerDay(#date,#EmployeeID) as numberOFWorkingHour
FETCH NEXT FROM dte_Cursor INTO #date
END
CLOSE dte_Cursor;
DEALLOCATE dte_Cursor;
end
And The Part of the Function Code that get the error is:
SET #From = (SELECT Time from #Tbl where date = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPIN')
set #to = (CASE WHEN EXISTS(SELECT Times from #Tbl where dates = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT' )
then (SELECT Time from #Tbl where date = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT' )
else (SELECT Top 1 Time from #Tbl where date = dateadd(day,1,#Date) AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT')
end)
return ROUND(CAST(DATEDIFF(#From,#to) AS decimal)/ 60,2)
the following piece of code that get the error :
(CASE WHEN EXISTS(SELECT Times from #Tbl where dates = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT' )
IN this example the employee have two out punches like the below :
EMPID Date Time Status
123 2015-10-22 06:54:42 AM OUT
123 2015-10-22 04:35:02 PM OUT
So how to how to handle this state?
You can just change
(CASE WHEN EXISTS(SELECT Times from #Tbl where dates = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT' )
To this
(CASE WHEN EXISTS(SELECT top 1 Times from #Tbl where dates = #Date AND (EmployeeID=#employeeID OR ISNULL( #employeeID, '') = '') and funckey = 'EMPOUT' )

Return new query if rowcount = 0

How can I return a new query if my first query didn't return anything? I'm using ssis to execute a stored procedure, if the stored procedure didn't return anything it should pass a new query that will be then saved to a new ole db destination.
Sample Query:
Declare #DepartureDate DATETIME = '4/16/2013',
begin
select PassengerNumber,FromTime,ToTime,Remarks from table a where DepartureDate = #DepartureDate
if (##ROWCOUNT = 0)
begin
Select
'-' [PassengerNumber],
'00:00' [FromTime],
'00:00' [ToTime],
'No Mismatch' [Remarks]
end
End
My problem is that my ole db source returns the blank query instead of the new query provided by the if(##rowcount = 0). So no data is transferred to the ole db source.
how about using UNION?
SELECT PassengerNumber, FromTime, ToTime, Remarks
FROM tableA
WHERE DepartureDate = #DepartureDate
UNION ALL
SELECT '-' [PassengerNumber],
'00:00' [FromTime],
'00:00' [ToTime],
'No Mismatch' [Remarks]
WHERE 0 = (SELECT COUNT(*) FROM tableA WHERE DepartureDate = #DepartureDate)
DECLARE #count INT = -1;
SELECT #count = COUNT(*)FROM TABLE a;
IF (#count > 0)
BEGIN
SELECT PassengerNumber,FromTime,ToTime,Remarks FROM TABLE a;
END
ELSE
SELECT
'-' [PassengerNumber],
'00:00' [FromTime],
'00:00' [ToTime],
'No Mismatch' [Remarks];
END
END

Counting records with a specific date value

I want to get all records entered with specific day, for example today:
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date nvarchar = '2012-09-21'
AS
BEGIN
declare #dateStart nvarchar(50) = #date + ' 00:00:00.0'
declare #dateEnd nvarchar(50) = #date + ' 23:59:59.437';
declare #returnData table (allQueue int,inQueue int,outQueue int)
SELECT 'table1' as table_name, COUNT(*)
FROM Queue as Counts
UNION ALL
SELECT 'table2' as table_name,COUNT(*) FROM Queue as Counts
WHERE QueueDate BETWEEN #dateStart AND #dateEnd
AND QueueNumIn != 0
END
Edited :
I Edited my code now it works :
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
AS
BEGIN
declare #date2 datetime
set #date2= '2012-09-21'
SELECT 'AllQueue' as table_name, COUNT(*)
FROM Queue as sdfds
UNION ALL
SELECT 'InQueue' as table_name,COUNT(*)
FROM Queue as sdfds
WHERE QueueDate >=#date2
AND QueueNumIn != 0
UNION ALL
SELECT 'OutQueue' as table_name, COUNT(*) FROM Queue as sdfds
WHERE QueueDate >=#date2
AND QueueNumOut != 0
END
It returns three records:
One problem is that the second column has no name. Why? Also, I want to return just one record that has three rows, not 3 separate records that have 2 fields.
you need to cast your varchar to datetime. and i think you want to assign Counts alias to Count(*)
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date nvarchar = '2012-09-21'
AS
BEGIN
declare #dateStart DATETIME = CAST(#date AS DATETIME)
declare #dateEnd DATETIME = DATEADD(hh,24,CAST(#date AS DATETIME))
declare #returnData table (allQueue int,inQueue int,outQueue int)
select 'table1' as table_name,COUNT(*) as Counts from QUEUE AS tb1
union all
select 'table2' as table_name,COUNT(*) as Counts from QUEUE AS tb2 where QueueDate >= #dateStart and QueueDate < #dateEnd and QueueNumIn !=0
END
not sure why returning all if you only want those in the spetial date.
Also, is better not to use between in Dates
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
#date datetime = '2012-09-21'
AS
BEGIN
select count(*) as 'AllQueue' ,
sum(case when QueueDate >=#date and QueueNumIn != 0 THEN 1 else 0 end) as 'InQueue',
sum(case when QueueDate >=#date and QueueNumOut != 0 THEN 1 else 0 end) as 'OutQueue'
from Queue
END
this should work.
this will give you something like
Allqueue inqueue, outqueue
----------------------------------------------------
11 | 8 | 10
This Code Worked and is edited code from ElVieejo
ALTER PROCEDURE [dbo].[SP_GET_QUEUESINFO_BY_DATE]
AS
BEGIN
declare #date2 datetime
set #date2= '2012-09-21'
select COUNT(QueueID) ,
sum(case when QueueNumIn != 0 THEN 1 else 0 end) as 'InQueue',
sum(case when QueueNumOut != 0 THEN 1 else 0 end) as 'OutQueue'
from Queue where QueueDate >= #date2
END