Data according to time - sql

I have table1 in this data is
ID Name StartDate EndDate
1 Paris 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
2 UK 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
3 France 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
and sp is
ALTER procedure [dbo].[spdata]
#fromdate datetime,
#todate datetime,
#Region varchar(50)
as
Select (Select Sum(Convert(int,SF)) from RVU inner dbo.VI vh on RVU.FID = vh.FID WHERE vh.No = Q.No and ID in (
Select ID from RU WHERE CAST(StartDate as date)>= CAST(#fromdate as date) and CAST(EndDate as date)<= CAST(#todate as date)
)) as SF
from (
Select
S.Name,
S.No,
SUM(Case when s.Vme='Car' then total else 0 end) as CAR,
SUM(Case when s.Vme='Tin' then total else 0 end) as Tin,
SUM(Case when s.Vme='Cake' then total else 0 end) as Cake,
SUM(Case when s.Vme='Flow' then total else 0 end) as Flow,
SUM(Case when s.Vme='Unit' then total else 0 end) as Unit,
SUM(total) total ,
MAX(S.Speed) Speed
from (
Select vh.Name as Name,vh.No as No,VV.Vame,count(VV.Vme) as total, RV.SF as MA,
RV.Speed from VVU VV inner join RVU RV on VV.MID=RV.ID inner join RU RU on RV.ID=RU.ID
left join dbo.VI vh on RV.FID = vh.FID WHERE CAST(RU.StartDate as date)>= CAST(#fromdate as date) and CAST(RU.EndDate as date)<= CAST(#todate as date) and
RU.Name_C= #Name_C AND Vme <> '' Group By vh.Name, vh.No, VV.Vme, RV.SF,
RV.Speed ) S GROUP BY s.RegNo, s.Name) Q
from that sp when i enter parameters DATA IS
[spdata] '2016-07-01 00:00:00.000', '2016-07-31 23:59:59.000', 'pARIS'
Name No CAR Tin Cake Flow Unit total Speed SF
John 412 0 0 12 0 5 17 82 60
Mike 48 2 1 5 1 3 9 160 464
ACNme 438 0 1 5 2 3 11 10 264
XYZ 248 0 1 5 3 3 12 60 244
now i want when i change time '2016-07-01 00:00:00.000', '2016-07-31 23:59:59.000',
like this
'2016-07-01 02:02:00.000', '2016-07-31 12:59:59.000',
then records also reflect on this time means according to date plus time data will be display

Don't cast your StartDate , EndDate , #fromdate , #todate as Date.
`Alter procedure [dbo].[spdata]
#fromdate datetime,
#todate datetime,
#Region varchar(50)
as
Select (Select Sum(Convert(int,SF)) from RVU inner dbo.VI vh on RVU.FID = vh.FID WHERE vh.No = Q.No and ID in (
Select ID from RU WHERE StartDate >= #fromdate and EndDate <=#todate
)) as SF
from (
Select
S.Name,
S.No,
SUM(Case when s.Vme='Car' then total else 0 end) as CAR,
SUM(Case when s.Vme='Tin' then total else 0 end) as Tin,
SUM(Case when s.Vme='Cake' then total else 0 end) as Cake,
SUM(Case when s.Vme='Flow' then total else 0 end) as Flow,
SUM(Case when s.Vme='Unit' then total else 0 end) as Unit,
SUM(total) total ,
MAX(S.Speed) Speed
from (
Select vh.Name as Name,vh.No as No,VV.Vame,count(VV.Vme) as total, RV.SF as MA,
RV.Speed from VVU VV inner join RVU RV on VV.MID=RV.ID inner join RU RU on RV.ID=RU.ID
left join dbo.VI vh on RV.FID = vh.FID WHERE RU.StartDate >= #fromdate and RU.EndDate <= #todate and
RU.Name_C= #Name_C AND Vme <> '' Group By vh.Name, vh.No, VV.Vme, RV.SF,
RV.Speed
) S GROUP BY s.RegNo, s.Name) Q`

Related

Multiple SUM in one query with multiple where

I'm trying to write a SQL query that produces a table with summarized values for each year and month.
I have a table that looks something like this:
TABLENAME: TIME
id cID cDate cTime
1 254 2019-10-11 5
2 259 2019-10-13 4
3 268 2020-01-17 6
4 268 2020-01-18 9
5 271 2020-01-21 4
6 267 2020-02-19 8
And another table that looks like this:
TABLENAME: CASE
id name invoice status
254 Acme Yes finish
259 Tex NoFakt finish
268 Rex C Yes *Null*
267 Hydro *Null* open
271 Corp Yes finish
I want to have a query that returns the sum for each month like this:
Year Month RegTime Invoiced ToBeInvoiced
2019 10 5 5 0
2019 11 0 0 0
2019 12 0 0 0
2020 1 19 4 15
2020 2 8 0 8
Explanation of the output:
Year and Month are obvious
RegTime should be the sum of all TIME.cTime WHERE CASE.invoice <> 'NoFakt'
Invoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish'
ToBeInvoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish'
I have tried this query, but with this i need to loop a predefined year and month value in my programming code instead of simply having a sql statement that are doing all the work. ThereĀ“s got to be a simpler way than this...
select (select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice <> 'NoFakt' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS RegTime,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS Invoiced,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS ToBeInvoiced
Use conditional aggregation :
SELECT YEAR(T.cDate) AS YR, MONTH(T.cDate) AS Mnth,
SUM(CASE WHEN C.invoice <> 'NoFakt' THEN C.cTIME ELSE 0 END) AS RegTime,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status = 'finish' THEN C.cTIME ELSE 0 END) AS Invoiced,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status <> 'finish' THEN C.cTIME ELSE 0 END) AS ToBeInvoiced
FROM TIME T INNER JOIN
CASE C
ON T.cID = C.id
GROUP BY YEAR(T.cDate), MONTH(T.cDate);
Note: Do not use reserved keyword as Object Name.

Group by datepart and find total count of individual values of each record

This is table structure;
ID Score Valid CreatedDate
1 A 1 2018-02-19 23:33:10.297
2 C 0 2018-02-19 23:32:40.700
3 B 1 2018-02-19 23:32:30.247
4 A 1 2018-02-19 23:31:37.153
5 B 0 2018-02-19 23:25:08.667
...
I need to find total number of each score and valid in each month
I mean final result should be like
Month A B C D E Valid(1) NotValid(0)
January 123 343 1021 98 12 1287 480
February 516 421 321 441 421 987 672
...
This is what I tried;
SELECT DATEPART(year, CreatedDate) as Ay,
(select count(*) from TableResults where Score='A') as 'A',
(select count(*) from TableResults where Score='B') as 'B',
...
FROM TableResults
group by DATEPART(MONTH, CreatedDate)
but couldn't figure how to calculate all occurrence of scores on each month.
Use conditional aggregation.
SELECT DATEPART(year, CreatedDate) as YR
, DATEPART(month, CreatedDate) MO
, sum(Case when score = 'A' then 1 else 0 end) as A
, sum(Case when score = 'B' then 1 else 0 end) as B
, sum(Case when score = 'C' then 1 else 0 end) as C
, sum(Case when score = 'D' then 1 else 0 end) as D
, sum(Case when score = 'E' then 1 else 0 end) as E
, sum(case when valid = 1 then 1 else 0 end) as Valid
, sum(case when valid = 0 then 1 else 0 end) as NotValid
FROM TableResults
GROUP BY DATEPART(MONTH, CreatedDate), DATEPART(year, CreatedDate)
I'm not a big fan of queries in the select; I find they tend to cause performance problems in the long run. Since we're aggregating here I just applied the conditional logic to all the columns.

T-SQL NULL-Friendly Query

I have a table "tblSalesOrder" in Microsoft T-SQL with some sample records:
SalesOrderID OrderDate ItemID Quantity PromotionCode
====================================================================
1 2014-09-01 100 5 NULL
2 2014-09-01 120 10 ABC
3 2014-09-05 150 7 NULL
4 2014-09-08 200 15 NULL
I need to return NULL-friendly resultset for records which do not exist.
As an example, I want a monthly query for September 2014:
SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM tblSalesOrder
WHERE OrderDate = BETWEEN '2014-09-01' AND '2014-09-30'
I need it to return at least 1 row for each day (i.e. 0 valued row, if the entry for that day is not available)
SalesOrderID OrderDate ItemID Quantity PromotionCode
====================================================================
1 2014-09-01 100 5 NULL
2 2014-09-01 120 10 ABC
0 2014-09-02 0 0 0
0 2014-09-03 0 0 0
0 2014-09-04 0 0 0
3 2014-09-05 150 7 NULL
0 2014-09-06 0 0 0
0 2014-09-07 0 0 0
4 2014-09-08 200 15 NULL
0 2014-09-09 0 0 0
...
...
...
0 2014-09-30 0 0 0
master..spt_values is a table in all microsoft sql databases containing 2506 rows, by cross joining, it will have 2506*2506 rows to calculate dates between from and to. Other tables can be used as well, this is just a table used to create the dates. A calendar table would be even easier to use.
The EXCEPT will remove all dates already in use. Then by combining the rows from tblSalesOrder and CTE with union all, empty days will be filled with the required hardcoded values:
DECLARE #from date = '2014-09-01'
DECLARE #to date = '2014-09-30'
;WITH CTE as
(
SELECT top (case when #to < #from then 0 else datediff(day, #from, #to) + 1 end)
dateadd(day, row_number() over (order by (select 1)) - 1, #from) OrderDate
FROM
master..spt_values t1
CROSS JOIN
master..spt_values t2
EXCEPT
SELECT
OrderDate
FROM
tblSalesOrder
)
SELECT
0 SalesOrderID, OrderDate, 0 ItemID, 0 Quantity, '0' PromotionCode
FROM
CTE
UNION ALL
SELECT
SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM
tblSalesOrder
ORDER BY
OrderDate, SalesOrderId
You can join the a date parameter in an empty select and coalesce the values:
select coalesce(t.SalesOrderID, 0) SalesOrderID
, coalesce(t.OrderDate, d.OrderDate) OrderDate
, coalesce(t.ItemID, 0) ItemID
, coalesce(t.Quantity, 0) Quantity
, coalesce(t.PromotionCode, 0) PromotionCode
from (select #dateParameter OrderDate) d
left
outer
join ( SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM tblSalesOrder
) t
on t.OrderDate = d.OrderDate
DECLARE #startDate date= '20140901'
,#endDate date = '20140930';
WITH Calendar as (
SELECT #startDate as OrderDate
UNION ALL
SELECT DATEADD(DAY, 1, OrderDate) as OrderDate
FROM Calendar
WHERE OrderDate < #endDate
)
SELECT coalesce(t.SalesOrderID, 0) SalesOrderID
, coalesce(t.OrderDate, Calendar.OrderDate) OrderDate
, coalesce(t.ItemID, 0) ItemID
, coalesce(t.Quantity, 0) Quantity
, CASE WHEN t.OrderDate IS NULL THEN '0' ELSE t.PromotionCode END as PromotionCode FROM Calendar
LEFT JOIN tblSalesOrder t ON Calendar.OrderDate = t.OrderDate
ORDER BY Calendar.OrderDate, t.SalesOrderID
OPTION (MAXRECURSION 0);

Fetch data in MS SQL 2008

I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name

sql timesheet count by day for the week

my table looks like this:
select clocktime, for_UID, in1_out0 from timeclockentries
clocktime for_UID in1_out0
2011-08-07 15:13:58.390 user193 1
2011-08-07 21:09:45.093 user193 0
2011-08-09 14:10:00.000 user193 1
2011-08-09 20:10:00.000 user193 0
I want the results to look like (assuming start of week is Saturday), separated by COLUMNS named 'day1', 'day2', etc.... (but for readability, i've typed them out with linefeeds) :
day1 day2 day3
1900-01-01 00:00:00.000 1900-01-01 05:55:46.700 1900-01-01 00:00:00.000
day4 day5 day6
1900-01-01 06:00:00.000 1900-01-01 00:00:00.000 1900-01-01 00:00:00.000
day7
1900-01-01 00:00:00.000
(i'm using sql2005)
below is what i'm using for a single day:
CREATE PROCEDURE [dbo].[sp_gethoursbyday]
#whichforUID varchar(20),
#whichdate datetime
AS
BEGIN
;WITH CTE as(
SELECT
DENSE_RANK() over (Partition by for_UID , in1_out0 Order by clocktime) id,
clocktime,
for_UID,
in1_out0
FROM
kdhcastle.dbo.timeclockentries tc
WHERE
tc.for_UID = #whichforUID
and month(tc.[clocktime]) = month(#whichdate)
and day(tc.[clocktime]) = day(#whichdate)
and year(tc.[clocktime]) = year(#whichdate)
)
SELECT
Cast(cast(sum(
cast(outTime.clocktime as float) - cast(inTime.clocktime as float)
)as datetime) as datetime) as 'hoursbydy'
FROM
CTE inTime
INNER JOIN CTE outTime
ON inTime.for_UID = outTime.for_UID
AND inTime.id = outTime.id
AND inTime.in1_out0 = 1
and outTime.in1_out0 = 0
END
SELECT
SUM(CASE WHEN DayOfWeek = 1 THEN Duration ELSE 0 END) AS Day1,
SUM(CASE WHEN DayOfWeek = 2 THEN Duration ELSE 0 END) AS Day2,
SUM(CASE WHEN DayOfWeek = 3 THEN Duration ELSE 0 END) AS Day3,
SUM(CASE WHEN DayOfWeek = 4 THEN Duration ELSE 0 END) AS Day4,
SUM(CASE WHEN DayOfWeek = 5 THEN Duration ELSE 0 END) AS Day5,
SUM(CASE WHEN DayOfWeek = 6 THEN Duration ELSE 0 END) AS Day6,
SUM(CASE WHEN DayOfWeek = 7 THEN Duration ELSE 0 END) AS Day7
FROM
(
SELECT
DATEDIFF(DAY, '2011 Jan 01', clocktime) % 7 + 1 AS DayOfWeek,
CAST(MAX(clocktime) - MIN(clocktime) AS FLOAT) AS Duration
FROM
yourTable
GROUP BY
for_UID,
DATEDIFF(DAY, '2011 Jan 01', clocktime)
)
AS [data]
This is more verbose but my focus was (a) to avoid repeating expressions and (b) to simulate all of the input parameters intended to be fed to the stored procedure so that the results are filtered on the desired user / date. Note that the #whichdate parameter is reeled back to the preceding Saturday at midnight, regardless of which day of the week it is or what time is associated with it.
Input parameters:
DECLARE #whichdate DATETIME;
SET #whichdate = '2011-08-08T12:34:00';
DECLARE #whichforUID VARCHAR(32);
SET #whichforUID = 'user193';
Body (just comment out the DECLARE #t / INSERT #t lines, and change #t in the first CTE to the real table name:
SET #whichdate = DATEADD(DAY, -DATEPART(WEEKDAY, #whichdate), #whichdate);
SET #whichdate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, #whichdate));
DECLARE #t TABLE(clocktime DATETIME, for_UID VARCHAR(32), in1_out0 BIT);
INSERT #t SELECT '2011-08-07 15:13:58.390','user193',1
UNION ALL SELECT '2011-08-07 21:09:45.093','user193',0
UNION ALL SELECT '2011-08-09 14:10:00.000','user193',1
UNION ALL SELECT '2011-08-09 20:10:00.000','user193',0;
WITH s(dw, ct, in1_out0) AS
(
SELECT 1 + (DATEDIFF(DAY, '2011-01-01', clocktime) % 7),
clocktime, in1_out0 FROM #t
where for_UID = #whichforUID
AND clocktime >= #whichdate
AND clocktime < DATEADD(DAY, 7, #whichdate)
),
d(dw, min_ct, max_ct) AS
(
SELECT dw,
MIN(CASE WHEN in1_out0 = 1 THEN ct ELSE NULL END),
MAX(CASE WHEN in1_out0 = 0 THEN ct ELSE NULL END)
FROM s GROUP BY dw
),
x AS
(
SELECT d = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, min_ct, max_ct), 0),
dw FROM d
),
pvt AS (
SELECT * FROM x PIVOT
(MAX(d) FOR dw IN ([1],[2],[3],[4],[5],[6],[7])) AS p
)
SELECT
day1 = COALESCE([1], '19000101'),
day2 = COALESCE([2], '19000101'),
day3 = COALESCE([3], '19000101'),
day4 = COALESCE([4], '19000101'),
day5 = COALESCE([5], '19000101'),
day6 = COALESCE([6], '19000101'),
day7 = COALESCE([7], '19000101')
FROM pvt;