sql query to count data entry of each hour - c#

I want to display the count of data entry of the present day during each hour(1 hour time interval) for a particular line and finally the cumulative of all the hours.
Table details:
CREATE TABLE [dbo].[ProductTable] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[ProductID] INT NOT NULL,
[EmployeeID] INT NOT NULL,
[Operation] VARCHAR (50) NOT NULL,
[Section] NCHAR (10) NOT NULL,
[Line] INT NOT NULL,
[Date] DATETIME DEFAULT (getdate()) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
);
I am using Microsoft Visual Studio SQL server
I have written so much but don't know to generalise for every hour
SELECT COUNT(Id) AS Expr1
FROM ProductTable
WHERE (Line = 2)
AND (CONVERT(VARCHAR(10), Date, 105) = CONVERT(VARCHAR(10), GETDATE(), 105))
AND (DATEPART(hour, GETDATE()) BETWEEN 9 AND 10)`
ProductTable data
Error on using "case"

it sounds like you want to group by the hour of the day
SELECT DATEPART(hour, date) as TimeOfDay, COUNT(Id) AS Entries
FROM ProductTable
WHERE (Line = 2) AND cast ([date] as date) =cast (getdate() as date)
GROUP BY DATEPART(hour, date)
To get the cumulative of all hours of the day, use grouping sets
SELECT ISNULL(cast(DATEPART(hour,[date]) as varchar(5)),'Total') as TimeOfDay, COUNT(Id) AS Entries
FROM ProductTable
WHERE (Line = 2) AND cast ([date] as date) =cast (getdate() as date)
GROUP BY GROUPING SETS (DATEPART(hour, [date]) , ())
ORDER BY ISNULL(cast(DATEPART(hour, [date]) as varchar(5)),'Total')

simply use group by clause
SELECT COUNT(Id) AS Expr1
FROM ProductTable
where (Line = 2) AND (CONVERT(Date,[Date])) = CONVERT(DATE,GETDATE())
GROUP BY DATEPART(HOUR, Date)

Related

Counting field by day in mssql

I have a table with Scheduling slots called:
ScheduleSlots
Fields:
id (int)
scheduleID (int)
time (datetime)
availableslots (int)
CalendarGroupID (int)
Level (int)
enabled (bit)
I want to setup a gridview where I take all of the dates and count enabled and disabled for each day.
I am not sure how to go about writing the sql statement to do this.
ie.
Date Enabled Disabled
3/31/2021 20 20
4/1/2021 10 30
SELECT Time, scheduleID,
(SELECT COUNT(Enabled) FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1 AND Enabled=1) as Enabled,
(SELECT COUNT(Enabled) FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1 AND Enabled=0) as Disabled
FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1
GROUP BY scheduleID, Time
The results I end up with:
[Results][1]
You could do it without inner selects:
SELECT [Time],
SUM([Enabled]) as [Enabled],
SUM([Disabled]) as [Disabled]
FROM [dbo].[ScheduleSlots]
WHERE
[Time]>='2021-03-31'
AND [Time]<='2021-04-01'
AND CalendarGroupID=1
AND Level=1
GROUP BY Cast([Time] as Date)
It is an easy grouping query:
SELECT
CONVERT(DATE, "Time") AS "Date",
SUM(CONVERT(INT, "Enabled")) AS "Enabled",
COUNT() - SUM(CONVERT(INT, "Enabled")) AS "Disabled"
FROM "dbo"."ScheduleSlots"
WHERE "CalendarGroupID" = 1
AND "Level" = 1
GROUP BY CONVERT(DATE, "Time")
I hope I understand you correctly where you want the enable slot and diable slot for each day.
;With CTE(Transdate) as (Select Distinct([time]) from ScheduleSlots)
Select CTE.Transdate,(Select COUNT(Id) from ScheduleSlots where enabled= 1
and Transdate = CTE.Transdate) as Enable,
(Select COUNT(Id) from ScheduleSlots where enabled= 0
and Transdate = CTE.Transdate) as Disable from CTE
I inserted some records to make it clear. If I am wrong with inserted data please send me the insert scripts so, that I can test the results.
CREATE TABLE ScheduleSlots
(
id int,
scheduleID int,
[time] datetime,
availableslots int,
CalendarGroupID int,
[Level] int,
[enabled] bit
)
----insert into ScheduleSlots values(1,1,'2021-03-31',40,1,1,20)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,0)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-04-01',40,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-04-01',40,1,1,0)
SELECT DISTINCT
[time] AS [Date]
,SUM(availableslots) OVER(PARTITION BY [time] ORDER BY [time]) AS [avaibale]
,SUM(CAST([enabled] AS INT)) OVER(PARTITION BY [time] ORDER BY [time]) AS [Enabled]
,SUM(availableslots) OVER(PARTITION BY [time] ORDER BY [time]) -
SUM(CAST([enabled] AS INT)) OVER(PARTITION BY [time] ORDER BY [time]) AS [Disabled]
FROM ScheduleSlots
Answer I got:

How to use limit the results returned from SQL Server using ROW_NUMBER()

I have database as below
CREATE DATABASE Test2;
CREATE TABLE table1
(
name nvarchar(50),
year int,
total1 int,
total2 int
);
INSERT INTO table1 (name, year, total1,total2)
VALUES ('a', 2020, 25,3);
INSERT INTO table1 (name, year, total1,total2)
VALUES ('b', 2018, 33,4);
INSERT INTO table1 (name, year, total1,total2)
VALUES ('c', 2020, 10,3);
INSERT INTO table1 (name, year, total1,total2)
VALUES ('b', 2018, 7,2);
INSERT INTO table1 (name, year, total1,total2)
VALUES ('a', 2020, 20,6);
I want to limit the results returned from SQL Server (take 2nd row and 3rd row) with this code
select
*
from
(select
year, name,
sum(total1) as "sum_Total1",
sum(total2) as "sum_Total2",
round((cast(isnull(sum(total2), 0) as float)) / (cast(sum(total1) as float)), 3) as "sum_Total2/sum_Total1",
row_number() over (order by round((cast(isnull(sum(total2), 0) as float)) / (cast(sum(total1) as float)), 3) asc) as no
from
Table_1
group by
name, year
order by
round((cast(isnull(sum(total2), 0) as float)) * 100 / (cast(sum(total1) as float)), 3) asc) a
where
a.no > 1 and a.no < 3
SQL Server return an error:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
Actually since you have already used the Order By in this line ROW_NUMBER() over(ORDER BY ROUND you don't need to use it again in your inner query after grouping. So all that you need to do is removing the unnecessary order by after your group by keyword.
Also FYI, I can see that you've queried from Table_1 while your table name is table1, so you need to fix it as well.
there are two issues:
You are not using the same table which you created.
to get the 2nd and 3rd row, you'll need to change the condition a.no < 3 to a.no <= 3
there is no use of order by clause as we have no.
Finally:
SELECT *
FROM
(
SELECT year,
name,
SUM(total1) AS "sum_Total1",
SUM(total2) AS "sum_Total2",
ROUND((CAST(ISNULL(SUM(total2), 0) AS FLOAT)) / (CAST(SUM(total1) AS FLOAT)), 3) AS "sum_Total2/sum_Total1",
ROW_NUMBER() OVER(
ORDER BY ROUND((CAST(ISNULL(SUM(total2), 0) AS FLOAT)) / (CAST(SUM(total1) AS FLOAT)), 3) ASC) AS no
FROM Table1
GROUP BY name,
year
--ORDER BY ROUND((CAST(ISNULL(SUM(total2), 0) AS FLOAT)) * 100 / (CAST(SUM(total1) AS FLOAT)), 3) ASC
) a
WHERE a.no > 1
AND a.no <= 3;
Just move the order by outside your subquery:
select *
from
(
select year ,name,
sum(total1) as "sum_Total1",
SUM(total2) as "sum_Total2",
ROUND((CAST(ISNULL(sum(total2),0) as float))/
(CAST(sum(total1) as float)),3) as "sum_Total2/sum_Total1",
ROW_NUMBER() over (ORDER BY
ROUND((CAST(ISNULL(sum(total2),0) as float))/ (CAST(sum(total1) as float)),3) ASC ) as no
from Table1
group by name, year
) a
where a.no > 1 and a.no < 4
order by no;

How to get the difference between time on same table but on different lines

I would like to know how to get the difference between time if the data is in the same table but on two separate lines. For example, below I have a screenshot of the data, every employee have two records, the first clock point and the last clock point. I want the difference between those times and save it into a new table. How do I do that?
Table structure:
CREATE TABLE [dbo].[RefinedData](
[ClockNo] [nvarchar](50) NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Department] [nvarchar](50) NULL,
[ClockPoint] [nvarchar](50) NULL,
[Date] [nvarchar](50) NULL,
[Time] [int] NULL
) ON [PRIMARY]
Layout of Data:
So in this case I want the time difference of the user Gerard saved in a new table but only one record per user.
It is apparent from your sample data , you have 2 rows of data per user.
row_number will work for you. Subtracting rn2-rn1 will return required output
with cte as
(select [ClockNo] ,
[FirstName] ,
[LastName] ,
[Department] ,
[ClockPoint] ,
[Date] ,
time,
ROW_NUMBER() over partition by clockno,firstname order by date,time) rn
from mytable
)
select c.[ClockNo] ,
c.[FirstName] ,
c.[LastName] ,
c.[Department] ,
c.[ClockPoint] ,
c.[Date] ,
c1.time -c.time
from cte c inner join (select * from cte where rn= 2) c1
on c.rn = c1.rn-1 and c.firstname = c.firstname and c.clockno = c1.cloclno
where c.rn = 1
You could do the following:
var differences =
refinedData.GroupBy(d => d.ClockNo)
.Select( g => g.OrderBy(d => d.Time))
.Select( g => new {
ClockNo = g.ClockNo,
Difference = g.Last() - g.First() });
try this-
select Firstname,cast(max(Time)-min(Time) as time) as 'time difference'
into #temptable
from RefinedData
where FirstName like 'Gerard'
and Date like '20180301'
group by Firstname
Here something you can start with:
select *, datediff(hour, LAG([Datetime]) over (partition by FirstName, LastName order by [Datetime]), [Datetime]) [Difference_in_hours]
from (
select FirstName,
LastName,
ClockPoint,
--get correctly formatted date column
cast(stuff(STUFF([DATE], len([DATE]) - 3, 0, '-'), len([DATE]), 0, '-') + ' ' + stuff(STUFF([time], len([time]) - 3, 0, ':'), len([time]), 0, ':') as datetime) [Datetime]
from [RefinedData]
) a where
ClockPoint like '% out %' or
ClockPoint like '% in %' or
ClockPoint like '% out' or
ClockPoint like '% in' or
ClockPoint like 'out %' or
ClockPoint like 'in %'

How to get the first and last row of data per user

I'm trying to write a query to select only the first and last record for each user.
Basically I want to:
SELECT * FROM EmpData WHERE ClockNo is DISTINCT AND only the first and last record
is displayed like in the picture. N.B it's color-coded per user
Database:
CREATE TABLE [dbo].[EmpData](
[ClockNo] [nvarchar](50) NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Department] [nvarchar](50) NULL,
[ClockPoint] [nvarchar](50) NULL,
[Date] [nvarchar](50) NULL,
[Time] [nvarchar](50) NULL
) ON [PRIMARY]
There are multiple approaches to doing this. But having the date/time values are in two columns makes this a hard problem. So, most methods involve date manipulations -- which can be quite database dependent.
Here is a method that requires no date/time manipulations. And, it should perform pretty well on most databases with the appropriate indexes:
select t.*
from t
where not exists (select 1
from t t2
where t2.clockno = t.clockno and
(t2.date > t.date or
t2.date = t.date and t2.time > t.time
)
) or
not exists (select 1
from t t2
where t2.clockno = t.clockno and
(t2.date < t.date or
t2.date = t.date and t2.time < t.time
)
) ;
If you want the data per day, then I would go for:
select t.*
from t join
(select clockno, date, min(time) as mint, max(time) as maxt
from t
group by clockno, date
) tt
on tt.clockno = t.clockno and tt.date = t.date and
t.time in (tt.mint, tt.maxt);

Find Difference between end dates by comparing rows

i have a table
----------
User
----------
userID(pk)
startdate // update : i am not using this field.
enddate
i need to compare between the end_dates between the rows comparing whether it is more than 3 days and count the userid.
i am doing something similar to this
WHILE ##FETCH_STATUS = 0
BEGIN
select #lastrowID = max(rowid) from #User
if (#userid = (select userId from #User where rowid = #lastRowID))
begin
update #User set NextEndDate= #endDate where rowid = #lastRowID and userid = #userid
end
else
begin
insert #UserTable (userid, EndDate,NextEndDate) values (#userid, #endDate,#NextEndDate)
end
END
my idea is to loop around the table and create a nextend date and then find the comparing using datediff. i am stuck with the first part of creating nextend date and i believe the 2nd part of comparing would be easy. i am stuck in between.
my question is am i doing the right thing, its getting pretty complicated.
i am confused whether to get the result through sql query or use C# at code behind using Linq or something similar.
Update:
sorry If i wasn't clear in explaining my scenario : i am trying to find the count, no of times a client has visited.
ex:
userid: 1 have may a visited daily or once in a month. so i need to get the count(frequency of the user visit). so if the users visited end date was
userid enddate
1 1/1/2010
1 1/2/2010 count 1
1 1/10/2010 count 2 difference is more than 3 days
1 1/13/2010 count 2 ( because diff is less than 3 days)
thats how i should count, thats y i was trying to use cursor which was too complicate for me to solve. I appreciate for your guidance.
Ok, I understand your problem now. I know there is a better way to do this in SQL, maybe with CTEs, but this solution should work and doesn't use cursors. This will give you a full table with the datediff of the previous enddate (where applicable). You can then select from it based on the datediff.
select u1.*, datediff(day, u2.enddate, u1.enddate) as days from
(
select userid, enddate, row_number() over(partition by userid order by userid, enddate) as rownumber
from [user]
) u1
left join
(
select userid, enddate, row_number() over(partition by userid order by userid, enddate) as rownumber
from [user]
)u2
on u1.userid = u2.userid
and u1.rownumber = u2.rownumber + 1
EDIT
declare #table table (userid int, startdate datetime, enddate datetime)
insert into #table (userid, startdate, enddate) values (1, '01-JAN-2010', '2-JAN-2010')
insert into #table (userid, startdate, enddate) values (2, '01-JAN-2010', '3-JAN-2010')
insert into #table (userid, startdate, enddate) values (3, '01-JAN-2010', '4-JAN-2010')
insert into #table (userid, startdate, enddate) values (4, '01-JAN-2010', '5-JAN-2010')
insert into #table (userid, startdate, enddate) values (5, '01-JAN-2010', '6-JAN-2010')
insert into #table (userid, startdate, enddate) values (6, '01-JAN-2010', '7-JAN-2010')
insert into #table (userid, startdate, enddate) values (7, '01-JAN-2010', '8-JAN-2010')
select SUM(yn) as dueinmorethanthreedays from
(select
(case when DATEADD(day,3,startdate) < enddate then 1 else 0 end) as yn
from #table
) as derived
A subquery which returns 1 for each row where the startdate is less than three days of the enddate (and 0 otherwise) can be summed to get the total.

Categories

Resources