Counting field by day in mssql - c#

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:

Related

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 can i run sqlserver trigger from C#

I have multiple trigger in a single sqlserver table some create description of a product by concatenating different fields, some get data from another table and a trigger which insert a product to another table.
I want to run the trigger which insert's data to another database table on button click from C#.
here is my code which inserts or setup product into another table
Create TRIGGER [dbo].[WHL-MISYSSETUP]
ON [dbo].[WHEELS]
AFTER insert,UPDATE
AS
BEGIN
IF TRIGGER_NESTLEVEL() > 1
RETURN
---------------------------------------------------// INSERT PRODUCT INFO TO MASTER TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
BEGIN
IF NOT EXISTS (SELECT * FROM [MITESTCO].dbo.[MIITEM]
WHERE [MITESTCO].dbo.[MIITEM].itemId IN (select [STOCK NO] from inserted) and [MITESTCO].dbo.[MIITEM].descr IN (select [PURCHASE DESCRIPTION] from inserted))
BEGIN
INSERT INTO [MITESTCO].dbo.MIITEM
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])--,[unitWgt]
SELECT [STOCK NO], [PURCHASE DESCRIPTION2], [SALES DESCRIPTION2], [STOCK NO] ,'EA' ,'EA' ,'1',[WORK INSTRUCTION-WHL], '2','0'--,[APPROX. WGT.]
FROM [inserted]
WHERE [STOCK NO] NOT IN (SELECT [itemId] FROM [MITESTCO].dbo.[MIITEM] WHERE itemId NOT LIKE '*-CI')
AND [MAKE / BUY]='Make';
END
END
SET ANSI_WARNINGS ON;
SET ANSI_WARNINGS off;
BEGIN
IF NOT EXISTS (SELECT * FROM [MITESTCO].dbo.[MIITEM]
WHERE [MITESTCO].dbo.[MIITEM].itemId IN (select [STOCK NO] from inserted) and [MITESTCO].dbo.[MIITEM].descr IN (select [PURCHASE DESCRIPTION] from inserted))
BEGIN
INSERT INTO [MITESTCO].dbo.MIITEM
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])--,[unitWgt]
SELECT [STOCK NO], [PURCHASE DESCRIPTION2], [SALES DESCRIPTION2], [STOCK NO] ,'EA' ,'EA' ,'1',[WORK INSTRUCTION-WHL], '2','0'--,[APPROX. WGT.]
FROM [inserted]
WHERE [STOCK NO] NOT IN (SELECT [itemId] FROM [MITESTCO].dbo.[MIITEM] WHERE itemId NOT LIKE '*-CI')
AND [MAKE / BUY]='BUY';
END
END
SET ANSI_WARNINGS on;
---------------------------------------------------// INSERT PRODUCT INFO TO BOM HEADER TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
DECLARE #d DATETIME = GETDATE();
INSERT INTO [MITESTCO].[dbo].[MIBOMH]
([bomItem], [bomRev], [rollup], [mult], [autoBuild], [assyLead],[revCmnt],[author],[descr],[qPerLead],[lstMainDt],[revDate],[effStartDate],[ovride] )
-- DECLARE #d DATETIME = GETDATE();
SELECT [STOCK NO], [bomRev], '1', '1', '1', '3','SYNC FROM TV','username','WHL FROM PDM','0', FORMAT(#d, 'yyyy-MM-dd HH\:mm\:ss\.fff', 'en-US') AS 'Format#1',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2','0'
FROM [INSERTED]
WHERE [STOCK NO] NOT IN (SELECT [MITESTCO].[dbo].[MIBOMH].[bomItem] FROM [MITESTCO].[dbo].[MIBOMH] where bomRev != [bomRev])
AND [STOCK NO] IN (SELECT [MITESTCO].[dbo].[MIITEM].[ItemId] FROM [MITESTCO].[dbo].[MIITEM] where type='2');
SET ANSI_WARNINGS ON;
---------------------------------------------------// INSERT PRODUCT INFO TO BOM DETAIL TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
;with cte as (
select
[STOCK NO]
, u.rev
, bomEntry = row_number() over (order by u.ordinal)
, u.Partid
, u.Qty--='1'
, cmnt = ''
, srcLoc = 'DS'
, dType = '0'
, lead = '0'
, lineNbr = row_number() over (order by u.ordinal)
--, bomRev
from [inserted]
cross apply (values
('1',[bomRev],1,[BOM-WHEEL PN])
,('1',[bomRev],2,[BOM - RIM PN])
,('1',[bomRev],3,[BOM - SECONDARY DISC PN])
,('1',[bomRev],4,[BOM - FIN DISC PN])
,('1',[bomRev],5,[BOM - FLAT FIN DISC PN])
,([WHL BOM QTY 1],[bomRev],6,[WHL BOM PART 1 PN])
,([WHL BOM QTY 2],[bomRev],7,[WHL BOM PART 2 PN])
,([WHL BOM QTY 3],[bomRev],8,[WHL BOM PART 3 PN])
,([WHL BOM QTY 4],[bomRev],9,[WHL BOM PART 4 PN])
,([WHL BOM QTY 5],[bomRev],10,[WHL BOM PART 5 PN])
,('1',[bomRev],11,[COLOR-PN])
) u (Qty,rev, ordinal, partId)
where nullif(u.partId, '') is not null
)
INSERT INTO [MITESTCO].dbo.[MIBOMD]
([bomItem], [bomRev], [bomEntry], [partId], [qty],[cmnt],[srcLoc],[dType],[lead],[lineNbr])
select
cte.[STOCK NO]
, cte.rev
, cte.bomEntry
, cte.Partid
, cte.Qty
, cte.cmnt
, cte.srcLoc
, cte.dType
, cte.lead
, cte.lineNbr
from cte
where not exists (
select 1
from [MITESTCO].dbo.[MIBOMD] w
where w.[bomItem] = cte.[STOCK NO]
and w.[bomRev] = cte.rev
and w.[bomEntry]= cte.bomEntry
);
SET ANSI_WARNINGS ON;
---------------------------------------------------// end Creates BOM STRUCTURE ----------------------------------------------------------------
The main reason that i want to run it manually or on button click event is because for some reason this trigger run before computed fields and some of the triggers so i don't get complete information to insert to the other table for the first time both after insert or update. i tried EXEC sp_settriggerorder #triggername=N'[dbo].[WHL-MISYSSETUP]', #order=N'Last', #stmttype=N'INSERT' but that doesnt help me i get the same problem
when new product created or updated i want to run this from C# on button click_event. Any idea will appreciated
Triggers can't be called. They should be triggered automatically and for every row, in your case:
AFTER insert,UPDATE.
If you need to run this query after clicking some button what I suggest is instead of using a trigger, create a new stored procedure.
The problem here is that you will have to know what are the [STOCK NO] you need to update without using the inserted table.

Calculate Absent of Student in SQL Server

i am updating an School Application in which i want to calculate absents of any student by their ID and selected time period. i have table in Sql Server named as CHECKINOUT that saves data of students. now i want to calculate absent of any student.when someone enters in school, an entry is made in this table with following fields
[USERID]
,[CHECKTIME]
,[CHECKTYPE]
this is screenshot of data in CHECKINOUT table
now say i have id 10 and i want to calculate absent of student during last month, i am confused in query. please help me in this
was working on it, not sure if this is the easiest but it works, i've tested it.
select missDates.userid, checkinout.userid, dt from
checkinout right join
(select * from (
SELECT DATEADD(DAY, nbr - 1, #StartDate) dt
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
FROM sys.columns c
) nbrs
WHERE nbr - 1 <= DATEDIFF(DAY, #StartDate, #EndDate)) alldates
cross join (select distinct userid from checkinout) t2) missDates
on missdates.userid = checkinout.userid
and convert(date,checktime) = convert(date,dt)
where checkinout.userid is null

Strange order of line insertion

I have a stored procedure that inserts a line in a table. This table has an auto incremented int primary key and a datetime2 column named CreationDate. I am calling it in a for loop via my C# code, and the loop is inside a transaction scope.
I run the program twice, first time with a for loop that turned 6 times and second time with a for loop that turned 2 times. When I executed this select on sql server I got a strange result
SELECT TOP 8
RequestId, CreationDate
FROM
PickupRequest
ORDER BY
CreationDate DESC
What I didn't get is the order of insertion: for example the line with Id=58001 has to be inserted after that with Id=58002 but this is not the case. Is that because I put my loop in a transaction scoope? or the precision in the datetime2 is not enough?
It is a question of speed and statement scope as well...
Try this:
--This will create a #numbers table with 1 mio numbers:
DECLARE #numbers TABLE(Nbr BIGINT);
WITH N(N) AS
(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1)
,MoreN(N) AS
(SELECT 1 FROM N AS N1 CROSS JOIN N AS N2 CROSS JOIN N AS N3 CROSS JOIN N AS N4 CROSS JOIN N AS N5 CROSS JOIN N AS N6)
INSERT INTO #numbers(Nbr)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM MoreN;
--This is a dummy table for inserts:
CREATE TABLE Dummy(ID INT IDENTITY,CreationDate DATETIME);
--Play around with the value for #Count. You can insert 1 mio rows in one go. Although this runs a while, all will have the same datetime value:
--Use a small number here and below, still the same time value
--Use a big count here and a small below will show a slightly later value for the second insert
DECLARE #Count INT = 1000;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
--A second insert
SET #Count = 10;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
SELECT * FROM Dummy;
--Clean up
GO
DROP TABLE Dummy;
You did your insertions pretty fast so the actual CreationDate values inserted in one program run had the same values. In case you're using datetime type, all the insertions may well occur in one millisecond. So ORDER BY CreationDate DESC by itself does not guarantee the select order to be that of insertion.
To get the desired order you need to sort by the RequestId as well:
SELECT TOP 8 RequestId, CreationDate
FROM PickupRequest
ORDER BY CreationDate DESC, RequestId DESC

Paginate SQL query

On a winform, in a datagrid, I am displaying about 100k rows, selected from the DB. Showing all these records take a lot of time. Is there a way to make the select query faster or maybe load the first 200 records. And then if the users click the next button, the next 200 records will be displayed. Is this possible? I know mysql has LIMIT, but I need something to work for sql-server 2008.
Stored Proc
Alter Proc Test
#PageNumber int,
#PageSize int
as
create table #t
(
id int
)
insert into #t(id)values(1)
insert into #t(id)values(2)
insert into #t(id)values(3)
insert into #t(id)values(4)
insert into #t(id)values(5)
insert into #t(id)values(6)
insert into #t(id)values(7)
insert into #t(id)values(8)
insert into #t(id)values(9)
insert into #t(id)values(10)
declare #StartIndex int
declare #EndIndex int
declare #PageSizeIndex int
Set #StartIndex = ((#PageNumber - 1) * #PageSize) + 1
Set #EndIndex = #PageNumber * #PageSize
Select RowID, ID From
(
Select ROW_NUMBER() Over(Order by id) as RowID, ID From #t
)K
Where K.RowID >= #StartIndex and k.RowID <= #EndIndex
Drop table #t
Testing Purpose Data testing
Test 1, 3
In addition to the above Stored Proc, You can implement Indexes to make the search fast or you can use SQL Profiler to check the reason for delay in execution time.
There's a method to it, but it's not pretty. If you're using Entity Framework, you can write LINQ to paginate results, something like:
var books= context.Books.OrderBy(b => b.Title).Skip(300).Take(100);
If you throw a SQL Profiler on it, the generated SQL will look something like the following, which you can use as a guide to build your own statement:
SELECT TOP (200)
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title]
FROM
(
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title],
row_number() OVER (ORDER BY [Extent1].[Title] ASC) AS [row_number]
FROM [dbo].[Books] AS [Extent1]
) AS [Extent1]
WHERE
[Extent1].[row_number] > 100
ORDER BY
[Extent1].[Title] ASC
There are several ways to do this, usually using a CTE or nested query and row_number().
See e.g.
How to do pagination in SQL Server 2008
And in SQL 2012, there is now the ability to do this in a single query at last, viz OFFSET xxx ROWS FETCH NEXT XXX ROWS ONLY - see Row Offset in SQL Server
You can use the a Common Table Expression, with the Row_Number ranking function. Here is an example:
CREATE PROCEDURE PagingSample
#PageNumber int,
#PageSize int
AS
WITH Results AS (
SELECT
ROW_NUMBER() OVER(ORDER BY MR.MRN ASC) As RowNumber,
MR.MRN
FROM
dbo.SomeTable MR WITH (NOLOCK)
)
SELECT
R.RowNumber,
R.MRN
FROM
Results R
WHERE
RowNumber > (#PageNumber * #PageSize) - #PageSize
AND RowNumber < (#PageNumber * #PageSize) + 1
Now pass the page number and the size of your page to the sproc, like so:
Exec PagingSample #PageNumber = 3, #PageSize = 100
And you will get records 201 through 300

Categories

Resources