Add two datetime columns and divide result by 2 in SQL Server - sql

If actual start date != ‘’ and complete date != '' calculate the mid trim date = (actual start date + complete date)/2
My table
CREATE TABLE [dbo].[AR_Placebook]
(
[Region] nvarchar(255) NULL,
[Network Area Description] [nvarchar](255) NULL,
[Substation] [nvarchar](255) NULL,
[Circuit] [nvarchar](255) NULL,
[Original (O) or Added Circuit (A)] [nvarchar](255) NULL,
[OC] [nvarchar](255) NULL,
[Line Miles] [float] NULL,
[Line Miles Complete] [float] NULL,
[Percent Complete] [float] NULL,
[Contractor] [float] NULL,
[Final Circuit Performance Audit] [nvarchar](255) NULL,
[Should Be Billed] [float] NULL,
[Invoiced to Date] [float] NULL,
[Gap in Billing Difference] [float] NULL,
[VCKT Number] [nvarchar](255) NULL,
[Bid Cost ] [float] NULL,
[Bid Cost per Line Mile] [float] NULL,
[Predictive Dialer Start Date] [nvarchar](255) NULL,
[ESTIMATED TRIM QUARTER] [nvarchar](255) NULL,
[Actual Start Date] [datetime] NULL,
[Complete Date] [datetime] NULL,
[MidTrimDate] [datetime] NULL
)
I have tried this
DECLARE #StartTime DATETIME
,#EndTime DATETIME
DECLARE #TotalWorkingHours varchar(50)
Declare #HalfDayCalculate varchar(50)
Declare #DivdeWorkingHours int
set #DivdeWorkingHours=2
SELECT #TotalWorkingHours = CONVERT(VARCHAR(8), DATEADD(SECOND,DATEDIFF(SECOND,#StartTime, #EndTime),0), 108)
from AR_Placebook
where #StartTime=[Actual Start Date] and
#EndTime =[Complete Date] and
[Actual Start Date]!='' and
[Complete Date]!=''
set #HalfDayCalculate = convert(TIME(0), dateadd(second, datediff(second, 0, #TotalWorkingHours) / #DivdeWorkingHours, 0),108)
select #HalfDayCalculate as MidTrimDate

You can go with different approach - calculate the date difference between the two dates using DATEDIFF (https://learn.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-ver15), divide the result of the DATEDIFF by 2 and subtract this value from the complete date.

Please find below the answer as per your requirement.
SELECT [start date],DATEADD(DAY,day_difference,[start date]) AS [mid_date],[complete date],day_difference
FROM
(
SELECT '2020-03-01' AS[start date], '2020-03-20' AS[complete date],DATEDIFF(DAY,'2020-03-01' ,'2020-03-20')/2 as day_difference
)A
Also, find below snap.
enter image description here

If actual start date != ‘’ and complete date != '' calculate the mid trim date = (actual start date + complete date)/2
I think you are looking for. For the middle day:
select dateadd(day,
datediff(day, start_date, complete_date) / 2,
start_date
)
If there is a time component, use a smaller time unit:
select dateadd(second,
datediff(second, start_date, complete_date) / 2,
start_date
)

Related

Create interval for recording

I have a table of schedule templates.
CREATE TABLE [dbo].[Template]
(
[ID] [uniqueidentifier] NOT NULL,
[Name] [nvarchar](50) NULL,
[Interval] [nvarchar](50) NULL,-- reception interval in minutes
[Activate] [bit] NOT NULL,-- is the template active or not
) ON [PRIMARY]
Therefore, only one template is active at any time, and for each template there is an n-th number of schedule intervals
CREATE TABLE [dbo].[Schedule]
(
[ID] [uniqueidentifier] NOT NULL,
[TemplateID] [uniqueidentifier] NULL,
[StartTime] [nvarchar](50) NULL, --start of available recording time
[EndTime] [nvarchar](50) NULL,--end of available recording time
[Monday] [bit] NULL,-- True or false whether the entry is available on Monday
[Tuesday] [bit] NULL,
[Wednesday] [bit] NULL,
[Thursday] [bit] NULL,
[Friday] [bit] NULL,
[Saturday] [bit] NULL,
[Sunday] [bit] NULL
) ON [PRIMARY]
I also have a table in which records and occupied time are already stored:
CREATE TABLE [dbo].[EventRecord]
(
[ID] [uniqueidentifier] NOT NULL,
[PeopleID] [uniqueidentifier] NULL,
[TemplateID] [uniqueidentifier] NULL,
[DateTime] [datetime] NULL,-- date and time of an already created entry
[Interval] [nvarchar](max) NULL,
[CheckOut] [bit] NULL,
[Details] [nvarchar](max) NULL
) ON [PRIMARY]
I need to write a stored procedure (query) that would return the available time for recording (if possible, in one query) given:
Reception interval
Already taken time by other records
Days of the week.
I can build the intervals of one Schedule, but how can I do this for all Schedules of one template and exclude the time for which I signed up.
DECLARE #intervalMinutes int = 10
DECLARE #myDates TABLE
(
startTime datetime,
endTime datetime
)
DECLARE #startTime DATETIME = '2016-07-10 08:00'
DECLARE #endTime DATETIME = '2016-07-10 22:00'
;WITH CTE AS
(
SELECT #startTime st
UNION ALL
SELECT DATEADD (MINUTE, #intervalMinutes, st) st
FROM cte
WHERE DATEADD (MINUTE, #intervalMinutes, st) < #endTime
)
SELECT st, DATEADD (MINUTE, #intervalMinutes, st)
FROM cte

How to implement dimension table design when having different values for the same dimension according to specific criteria?

If I have a Dimension Date table like this:
CREATE TABLE [Dimension].[Date](
[Date Key] [int] IDENTITY(1,1) NOT NULL,
[Date] [date] NOT NULL,
[Day] [tinyint] NOT NULL,
[Day Suffix] [char](2) NOT NULL,
[Weekday] [tinyint] NOT NULL,
[Weekday English Name] [varchar](10) NOT NULL,
[Weekday English Name Short] [char](3) NOT NULL,
[Weekday English Name FirstLetter] [char](1) NOT NULL,
[Weekday Arabic Name] [nvarchar](15) NOT NULL,
[Weekday Arabic Name FirstLetter] [nchar](1) NOT NULL,
[Day Of Year] [smallint] NOT NULL,
[Week Of Month] [tinyint] NOT NULL,
[Week Of Year] [tinyint] NOT NULL,
[Month] [tinyint] NOT NULL,
[Month English Name] [varchar](10) NOT NULL,
[Month English Name Short] [char](3) NOT NULL,
[Month English Name FirstLetter] [char](1) NOT NULL,
[Month Arabic Name] [nvarchar](15) NOT NULL,
[Month Arabic Name FirstLetter] [nchar](1) NOT NULL,
[Quarter] [tinyint] NOT NULL,
[Quarter Name] [varchar](6) NOT NULL,
[Year] [int] NOT NULL,
[MMYYYY] [char](6) NOT NULL,
[Month Year] [char](7) NOT NULL,
[Is Weekend] [bit] NOT NULL,
[Is Holiday] [bit] NOT NULL,
[Holiday Name] [nvarchar](50) NOT NULL,
[Special Day] [nvarchar](50) NOT NULL,
[First Date Of Year] [date] NULL,
[Last Date Of Year] [date] NULL,
[First Date Of Quater] [date] NULL,
[Last Date Of Quater] [date] NULL,
[First Date Of Month] [date] NULL,
[Last Date Of Month] [date] NULL,
[First Date Of Week] [date] NULL,
[Last Date Of Week] [date] NULL,
[Lineage Key] [int] NULL,
CONSTRAINT [PK__Date__B7A341C5SWWC2006D] PRIMARY KEY CLUSTERED
(
[Date Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
I face the following problem:
Not all weekends and holidays are the same for all the organizational departments, There are default weekends(Fri,Sat) for example but some departments have different schedules so they have different weekend days. How to handle this situation when I have different values for the same dimension according to specific criteria? Should I create multiple versions for the same Dim? How to use Date Dim as a conformed dimension in an enterprise data warehouse in this case?
Having the Date dimension as a conformed table is adavntageous when :
One central location to update by ETL jobs
Easy to implement “Single Source of Truth” because the same copy of
data is visible across organization.
Less data footprint due to removal of unnecessary copies of the same
data.
In your case, you don't need all the columns so you can have the DimDate table in your database but pointing to it with a simple view to get only columns you need.
Also, you can have a bridge table between the DimDate view and the DimDepartment like below :
A logical data model may contain one or more many-to-many relationships. Physical data modelling techniques transform a many-to-many many-relationships into one-to many-relationships by adding additional tables. These are referred to as bridge tables.

Count records where the date is last month

I have a table like this
And then I want to add a column besides Total column. The column is LastMonthTotal with the same record but the date is last month before. How can I do that?
Here's the DDL
CREATE TABLE [dbo].[ERA_Report2]
(
[RESULT] [nvarchar](255) NULL,
[CLASSIFICATION_2] [nvarchar](255) NULL,
[ARMADA] [nvarchar](255) NULL,
[CDAREA] [nvarchar](255) NULL,
[BRAND] [nvarchar](255) NULL,
[MODEL] [nvarchar](255) NULL,
[Shift] [nvarchar](255) NULL,
[AST_POINT] [nvarchar](255) NULL,
[SOURCE] [nvarchar](255) NULL,
[AREA] [nvarchar](255) NULL,
[POST DATE] [nvarchar](255) NULL,
[PRICE] [float] NULL,
[DISC] [float] NULL,
[Net Payment] [float] NULL
)
My query is like this:
WITH step1 AS (
SELECT [RESULT],[CLASSIFICATION_2],[ARMADA],[CDAREA],[BRAND],[MODEL],[Shift],[AST_POINT],[SOURCE],[AREA]
,CONVERT(DATE, [POST DATE]) AS [POST DATE],COUNT(*) AS Total
FROM [AstraWorldDB].[dbo].[ERA_Report2]
GROUP BY [RESULT],[CLASSIFICATION_2],[ARMADA],[CDAREA],[BRAND],[MODEL],[Shift],[AST_POINT],[SOURCE],[AREA]
,[POST DATE]
),
step2 AS (
SELECT [RESULT],[CLASSIFICATION_2],[ARMADA],[CDAREA],[BRAND],[MODEL],[Shift],[AST_POINT],[SOURCE],[AREA]
,[POST DATE],Total
,CASE
WHEN MONTH([POST DATE]) > DATEPART(MONTH, DATEADD(MONTH, -1, [POST DATE]))
THEN (SELECT COUNT(*)
FROM step1
WHERE DATEPART(MONTH, [POST DATE]) = DATEPART(MONTH, DATEADD(MONTH, -1, [POST DATE])) AND
DATEPART(YEAR, [POST DATE]) = DATEPART(YEAR, DATEADD(MONTH, -1, [POST DATE]))
)
ELSE '0'
END AS LastMonthTotal
FROM step1
)
SELECT *
FROM step2
WHERE AREA = 'DPS'
ORDER BY [POST DATE]
but it keeps returning 0 when it shouldn't. This is the result:
result
where POST DATE = 2020-02-01, LastMonthTotal must be 2.
In all supported versions of SQL Server, you would use LAG() -- assuming that every month has data:
select t.*,
lag(total) over (partition by [RESULT],[CLASSIFICATION_2], [ARMADA],[CDAREA], [BRAND], [MODEL], [Shift], [AST_POINT], [SOURCE], [AREA] order by [POST DATE]) as prev_month_total
from <your table> t;
This seems like a reasonable assumption.
In older versions, you would presumably use a join:
select t.*, tprev.total
from <your table> t left join
<your table> tprev
on tprev.result = t.result and . . . -- all the columns that define the group
tprev.post_date = dateadd(month, -1, t.post_date)

i want to get data through fromDate & toDate on employe code

here is my stored procedure...this stored procedure showing result for fromdate and toate on employee code,an aggregate function for differentiate checkIn and checkout...
it shows data for checkout time only for one date,the problem is ,I need this for multiple days...
If any one know what is the problem kindly share your experience with me, and point my mistakes in query...
I shall be thankful
here is the tables script
CREATE TABLE [dbo].[ras_AttRecord](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DN] [smallint] NULL,
[DIN] [bigint] NOT NULL,
[Clock] [datetime] NOT NULL,
[VerifyMode] [tinyint] NULL,
[AttTypeId] [char](3) NOT NULL,
[CollectDate] [datetime] NOT NULL,
[LastUpdatedUID] [int] NULL,
[LastUpdatedDate] [datetime] NULL,
[Remark] [nvarchar](64) NULL
)
CREATE TABLE [dbo].[ras_Users](
[UID] [int] NOT NULL,
[DIN] [bigint] NOT NULL,
[PIN] [varchar](32) NOT NULL,
[UserName] [nvarchar](64) NULL,
[Sex] [char](1) NOT NULL,
[Password] [nvarchar](32) NULL,
[PasswordQuestion] [nvarchar](64) NULL,
[PasswordAnswer] [nvarchar](32) NULL,
[IsApproved] [bit] NOT NULL,
[IsLockedOut] [bit] NOT NULL,
[CreateDate] [datetime] NULL,
[LastLoginDate] [datetime] NULL,
[DeptId] [varchar](64) NOT NULL,
[AttId] [char](4) NULL,
[RuleId] [char](4) NULL,
[WeekendId] [char](4) NULL,
[LastUpdatedUID] [int] NULL,
[LastUpdatedDate] [datetime] NOT NULL,
[Comment] [nvarchar](128) NULL
)
I'm using this stored procedure
ALTER PROCEDURE [dbo].[GetLateComersmonthly]
#FromDate DATE='05/22/2017',
#ToDate DATE='06/06/2017',
#Code varchar(6) ='3155'
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF #Code = '0'
SET #Code = null
-- Insert statements for procedure here
select
T1.UserName,
T1.DIN as [DIN],
min(T1.Date) as [Date],
min(T1.Time) as [Time],
CASE
WHEN max(T2.Time) = max(T1.Time) THEN ''
ELSE max(T2.Time) end as [Timee], min(T1.Day) as [Day],
CASE
WHEN concat(CONVERT(varchar,DATEDIFF(MINUTE,min(T1.Time),max(t2.Time)),108)/60,
':',
CONVERT(varchar,DATEDIFF(MINUTE,min(T1.Time),max(t2.Time))%60,108)) = '0:0'
THEN 'No Check Out'
ELSE concat(CONVERT(varchar,DATEDIFF(MINUTE,min(T1.Time),max(t2.Time)),108)/60,
':',
CONVERT(varchar,DATEDIFF(MINUTE,min(T1.Time),max(t2.Time))%60,108))
END AS hrs
from
(SELECT
UserName ,
ru.DIN,
CONVERT(varchar, Att.Clock, 101) AS Date,
CONVERT(varchar, Att.Clock, 108) AS Time,
att.VerifyMode as Mode, DATENAME(dw, Att.Clock) AS Day
FROM
ras_Users as ru
inner join ras_AttRecord as att ON ru.DIN = att.Din
where CONVERT(DATE,Clock) >= #FromDate
and CONVERT(DATE,Clock)<=#ToDate
and att.DIN = COALESCE (#Code, att.DIN)
and att.VerifyMode = 15
) as T1
left join
(SELECT
ru.DIN,
max(CONVERT(varchar, Att.Clock, 108)) AS Time
FROM
ras_Users as ru
inner join ras_AttRecord as att ON ru.DIN = att.Din
where CONVERT(DATE,Clock) >= #FromDate
and CONVERT(DATE,Clock)<=#ToDate
and att.DIN = COALESCE (#Code, att.din)
group by ru.DIN, att.Clock
) as T2 on T1.DIN = T2.DIN --and DATEDIFF(MINUTE,T1.Time,t2.Time)/60 < 9
group by
T1.Username,
T1.din,
T1.Day
-- having CONVERT(varchar, min(T1.Time), 108) > '09:30:00'
order by T1.din
END
its shows the following result
Current Record displaying
Userid Date CheckIn CheckOut Day total hours
3155 05/26/2017 09:15:10 17:15:00 Friday 8:0
3155 05/29/2017 09:08:36 17:15:00 Monday 8:7
3155 05/25/2017 09:34:28 17:15:00 Thursday 7:41
3155 05/30/2017 09:15:12 17:15:00 Tuesday 8:0
3155 05/31/2017 09:27:37 17:15:00 Wednesday 7:48
and I need the following result
Expected Result
Userid Date CheckIn CheckOut day total hours
3155 05/26/2017 09:15:10 17:00:00 Friday 8:0
3155 05/29/2017 09:08:36 17:05:00 Monday 8:7
3155 05/25/2017 09:34:28 17:30:00 Thursday 7:41
3155 05/30/2017 09:15:12 17:18:00 Tuesday 8:0
3155 05/31/2017 09:27:37 17:10:00 Wednesday 7:48

Can I make this stored procedure faster

I have the stored procedure below. This stored procedure runs in 3-4 seconds even on my developer computer but on the server it takes 15-20 seconds. I tried to change some of subqueries to cross apply and some to outer apply. But it caused to take more longer time.
#startDate datetime ,
#endDate datetime ,
#customerId int
;WITH t1(Plate,UsedFuelTypeUID,RemainingBefore,DateRangeTotal,DateRangeTransactionsTotal,RemaininCurrent) AS
(
select
v.Plate, v.UsedFuelTypeUID,
isnull((select isnull( sum(vls1.FT_TotalLimit),0)
from VehicleChildLog vls1
where vls1.VehicleChildId =v.VehicleID and vls1.UpdateDate < #startDate
),0)-
isnull((select isnull( sum(t1.Liter),0) from Transactions t1
where t1.VehicleChildID=v.VehicleID and t1.SaleDate <#startDate
),0)as RemainingBefore,
sum(vl.FT_TotalLimit) DateRangeTotal,
isnull((select isnull( sum(t1.Liter),0) from Transactions t1
where t1.VehicleChildID=v.VehicleID and t1.SaleDate between #startDate and #endDate
),0) as DateRangeTransactionsTotal,
(v.FT_TotalLimit - v.FT_UsedTotalLimit) as RemainingCurrent
from VehicleChildLog vl
inner join VehiclesChild v on vl.VehicleChildId = v.VehicleID
where vl.CustomerChildID = #customerId and vl.UpdateDate between #startDate and #endDate
group by
v.VehicleID, v.Plate, v.UsedFuelTypeUID
,v.FT_TotalLimit - v.FT_UsedTotalLimit
)
select *, t1.RemainingBefore+t1.DateRangeTotal-t1.DateRangeTransactionsTotal as RemainingAfter from t1 ;
Table structure is below
[Transactions]
(
[TransactionID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[SaleDate] [datetime] NULL,
[Liter] [float] NULL,
[VehicleChildID] [int] NULL
...
)
[VehiclesChild]
(
[VehicleID] [int] IDENTITY(1,1) NOT NULL,
[CustomerChildID] [int] NULL,
[Plate] [varchar](16) NULL,
[UsedFuelTypeUID] [int] NULL,
[FT_TotalLimit] [float] NULL,
[FT_UsedTotalLimit] [float] NULL
...
)
[VehicleChildLog]
(
[VehiclesChildLogId] [int] IDENTITY(1,1) NOT NULL,
[VehicleChildId] [int] NOT NULL,
[CustomerChildId] [int] NOT NULL,
[FT_TotalLimit] [float] NULL,
[FT_UsedTotalLimit] [float] NULL,
[UpdateDate] [datetime] NULL
...
)