How to check the previous row value - sql-server

Following is the model data in my table.
Data:
Date Worked Hours IsLate
8/1/2013 8:03:00 No
8/2/2013 10:52:00 No
8/3/2013 8:43:00 Yes
8/4/2013 9:26:00 No
IsLate column to be updated as 'Yes' if previous day worked hours is equal to 10 hours. How can I calculate the previous row value is equal to 10 hours or not.
Please help me out.

Query:
SQLFIDDLEExample
with table5
as (
SELECT Date,
[Worked Hours],
IsLate,
ROW_NUMBER() OVER (ORDER BY Date ASC, [Worked Hours] ASC) AS RowNumber1
FROM Table1
)
SELECT t1.Date,
t1.[Worked Hours],
t1.IsLate,
CASE WHEN LEFT(t2.[Worked Hours],2) = '10'
THEN 'Equal'
ELSE 'Not Equal' END AS isequal
FROM table5 t1
LEFT JOIN table5 t2
ON t1.RowNumber1 - 1 = t2.RowNumber1
Result:
| DATE | WORKED HOURS | ISLATE | ISEQUAL |
|-------------------------------|--------------|--------|-----------|
| August, 01 2013 00:00:00+0000 | 8:03:00 | No | Not Equal |
| August, 02 2013 00:00:00+0000 | 10:52:00 | No | Not Equal |
| August, 03 2013 00:00:00+0000 | 8:43:00 | Yes | Equal |
| August, 04 2013 00:00:00+0000 | 9:26:00 | No | Not Equal |
If you want just update table use this:
SQLFIDDLEExample
UPDATE Table1
SET [IsLate] = ISNULL((SELECT TOP 1 CASE WHEN LEFT(t1.[Worked Hours],2) = '10'
THEN 'Equal'
ELSE 'Not' END
FROM Table1 t1
WHERE t1.Date < Table1.Date
ORDER BY t1.Date DESC), 'Not')
Result:
| DATE | WORKED HOURS | ISLATE |
|-------------------------------|--------------|--------|
| August, 01 2013 00:00:00+0000 | 8:03:00 | Not |
| August, 02 2013 00:00:00+0000 | 10:52:00 | Not |
| August, 03 2013 00:00:00+0000 | 8:43:00 | Equal |
| August, 04 2013 00:00:00+0000 | 9:26:00 | Not |

IF 10 <= (SELECT DATEPART(hh, Worked_Hours) from Data)
Begin
Update Data set isLate = 'No'
where ..
End

update yourtable
set late='yes'
from yourtable
where
(select top 1 datepart(hh,worked)
from yourtable t2
where t2.workdate<yourtable.workdate order by workdate desc)=10

How about this?
declare #d table (WorkedDate date,WorkedHours time,IsLate varchar(10));
insert #d select '8/1/2013','8:03',null;
insert #d select '8/2/2013','10:52',null;
insert #d select '8/3/2013','8:43',null;
insert #d select '8/4/2013','9:26',null;
update #d set IsLate=case when exists (select WorkedHours from #d p where p.WorkedDate=dateadd(day,-1,d.WorkedDate) and WorkedHours>'10:00') then 'Yes' else 'No' end
from #d d;
select * from #d;

Related

MS Access Transform / Pivot to SQL Server with grouping

I know similar questions have been asked before, however the grouping is throwing me off and hopefully I can get some help. I currently have a working MS Access model that does custom calculations to an Oracle connection, however my data is now pushing the 2GB mark with the custom calculations and trying SQL Server Express as an alternative and need a bit of help.
The database structure is from a 3rd party application so have to live with what I have - its UGLY.
ID | ATRSTUDY | ENDTIME | NAME | COUNT
---+----------+--------------------+-------------+-------
1 | A | Jan 1, 18 00:15 | NorthBound | 10
2 | A | Jan 1, 18 00:15 | SouthBound | 20
3 | A | Jan 1, 18 00:15 | Both Dir | 30
4 | B | Jan 1, 18 00:15 | EastBound | 30
5 | B | Jan 1, 18 00:15 | WestBound | 40
5 | B | Jan 1, 18 00:15 | Both Dir | 70
My existing MS-Access SQL is:
TRANSFORM Sum(CountData_Local.Count) AS SumOfCount
SELECT CountData_Local.ATRSTUDY, DateValue([CountData_Local]![ENDTIME]) AS CNTDATE, CountData_Local.ENDTIME
FROM DataVariables, CountData_Local
GROUP BY CountData_Local.ATRSTUDY, DateValue([CountData_Local]![ENDTIME]), CountData_Local.ENDTIME
PIVOT IIf([NAME]="EastBound" Or [NAME]="NorthBound" Or [NAME]="First Direction","C1",IIf([NAME]="WestBound" Or [NAME]="SouthBound" Or [NAME]="Second Direction","C2",IIf([NAME]="Both Dir","TC")));
The end result I am try to achieve is a pivot table that combines the 3 rows into one row as follows:
ATRSTUDY | CNDDATE | ENDTIME | C1 | C2 | TC
---------+-----------+---------+----+----+---
A | Jan 1, 18 | 00:15 |10 | 20 | 30
B | Jan 1, 18 | 00:15 |30 | 40 | 70
Thanks in advance!
Here is my SQL to date. Still having a bit of trouble with showing date and time and adding a filter for a date range which I currently have filtered out.
Perfect situation, date would be a between A and B.
Select atrstudy, endtime, sum(c1), sum(c2), sum(tc) from
(
with t as
(
select
sdata.oid,
sdata.atrstudy,
case upper(datatyp.name)
when 'EASTBOUND' then 'C1'
when 'NORTHBOUND' then 'C1'
when 'FIRST DIRECTION' then 'C1'
when 'WESTBOUND' then 'C2'
when 'SOUTHBOUND' then 'C2'
when 'SECOND DIRECTION' then 'C2'
when 'BOTH DIRECTIONS' then 'TC'
else datatyp.name
end as namedir,
/* trunc(datadtlbs.starttime) as starttime, */
endtime as endtime,
datadtlbs.count as counttot,
sdata.gcrecord
from roy.atrstudydata sdata
left outer join roy.atrstudydatadtl datadtl
on sdata.oid = datadtl.parent
join roy.atrstudydattyp datatyp
on sdata.direction = datatyp.oid
left outer join roy.atrstudydatadtlbs datadtlbs
on datadtl.oid = datadtlbs.oid
/* where trunc(datadtlbs.endtime) > '31-DEC-15' can remove this where clause*/)
select atrstudy, endtime, C1, C2, TC from t
pivot
(sum(COUNTtot) for NAMEdir in ('C1' as C1, 'C2' as C2, 'TC' as TC)))
group by atrstudy, endtime
order by atrstudy, endtime
MS SQL Server has PIVOT to do such things.
And CASE can be used to group those names as codes.
Example snippet:
--
-- Using a table variable for easy testing in the example
--
declare #Count_data table (id int identity(1,1) primary key, ATRSTUDY varchar(1), ENDTIME datetime, NAME varchar(30), [COUNT] int);
insert into #Count_data (ATRSTUDY, ENDTIME, NAME, [COUNT]) values
('A','2018-01-01T18:00:15','NorthBound',10),
('A','2018-01-01T18:00:15','SouthBound',20),
('A','2018-01-01T18:00:15','Both Directions',30),
('B','2018-01-01T18:00:15','EastBound',30),
('B','2018-01-01T18:00:15','WestBound',40),
('B','2018-01-01T18:00:15','Both Directions',70);
select ATRSTUDY, ENDDATE, ENDTIME, [C1], [C2], [TC]
from (
select
d.ATRSTUDY,
cast(d.ENDTIME as date) as ENDDATE,
left(cast(d.ENDTIME as time),5) as ENDTIME,
(case -- if the Name column has a Case-Insensitive collation then lower or upper case won't matter.
when d.Name in ('eastbound', 'northbound', 'first direction') then 'C1'
when d.Name in ('westbound', 'southbound', 'second direction') then 'C2'
when d.Name like 'both dir%' then 'TC'
else d.Name
end) as ColName,
d.[count]
From #Count_data d
) as q
pivot (
sum([count])
for ColName in ([C1], [C2], [TC])
) as pvt
order by ATRSTUDY, ENDDATE, ENDTIME;
Output:
ATRSTUDY ENDDATE ENDTIME C1 C2 TC
-------- ---------- ------- -- -- --
A 2018-01-01 18:00 10 20 30
B 2018-01-01 18:00 30 40 70

SQL Find Tickets Open Between Start Date and End Date

I currently have the following table:
+-----+-----------------------------+------------------------------+
| ID | StartDate | EndDate |
+-----+-----------------------------+------------------------------|
| 1 | 2017-07-24 08:00:00.000 | 2017-07-29 08:00:00.000 |
| 2 | 2017-07-25 08:00:00.000 | 2017-07-28 08:00:00.000 |
| 3 | 2017-07-25 08:00:00.000 | 2017-07-26 08:00:00.000 |
+-----+-----------------------------+------------------------------+
I would like to know the count of the ID's that were not Closed on each date.
So for example, I wan't to know the count of open ID's on 2017-07-26 00:00:00.000. This would be all 3 in this case.
Another example: I wan't to know the count of open ID's on 2017-07-29 00:00:00.000. Which would be result to 1. Only ID=1 is Not yet closed at that date.
I have tried using another solution here on StackOverflow, but I can't quite figure why it is giving me false results.
declare #dt date, #dtEnd date
set #dt = getdate()-7
set #dtEnd = dateadd(day, 100, #dt);
WITH CTEt1 (SupportCallID, StartDate, EndDate, Onhold)
as
(SELECT SupportCallID
,OpenDate
,MAX(CASE WHEN StatusID IN('19381771-8E81-40C5-8E36-62A7DB0A2A99', '95C7A5FB-2389-4D14-9DAE-A08BFCC3B09A', 'D5429790-3B43-4462-9E1E-2466EA29AC74') then CONVERT(DATE, LastChangeDate) end) EndDate
,OnHold
FROM [ClienteleITSM_Prod_Application].[dbo].[SupportCall]
group by SupportCallID, OpenDate, OnHold
)
SELECT dates.myDate,
(SELECT COUNT(*)
FROM CTEt1
WHERE myDate BETWEEN StartDate and EndDate
)
FROM
(select dateadd(day, number, #dt) mydate
from
(select distinct number from master.dbo.spt_values
where name is null
) n
where dateadd(day, number, #dt) < #dtEnd) dates
If you use a cte to create a table of dates that span the range of dates in your source table, you can easily left join from that to your source table and count up the rows returned:
declare #t table(ID int,StartDate datetime,EndDate datetime);
insert into #t values (1,'2017-07-24 08:00:00.000','2017-07-29 08:00:00.000'),(2,'2017-07-25 08:00:00.000','2017-07-28 08:00:00.000'),(3,'2017-07-25 08:00:00.000','2017-07-26 08:00:00.000');
declare #StartDate datetime = (select min(StartDate) from #t);
declare #EndDate datetime = (select max(EndDate) from #t);
-- Table with 10 rows in to be joined together to create a large tally table (10 * 10 * 10 * etc)
with t(t) as (select t from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(t))
-- Add the row_number of the tally table to your start date to generate all dates within your data range
,d(d) as (select top(datediff(d,#StartDate,#EndDate)+1) dateadd(d,row_number() over (order by (select null))-1,#StartDate) from t t1,t t2,t t3)
select d.d
,count(t.ID) as OpenIDs
from d
left join #t as t
on(d.d between cast(t.StartDate as date) and t.EndDate)
group by d.d
order by d.d;
Output:
+-------------------------+---------+
| d | OpenIDs |
+-------------------------+---------+
| 2017-07-24 08:00:00.000 | 1 |
| 2017-07-25 08:00:00.000 | 3 |
| 2017-07-26 08:00:00.000 | 3 |
| 2017-07-27 08:00:00.000 | 2 |
| 2017-07-28 08:00:00.000 | 2 |
| 2017-07-29 08:00:00.000 | 1 |
+-------------------------+---------+

Using a condition for cross join on months

Table 1 has column date , value
Table 2 has monthnumber , monthname (ie 1-12 for number and Jan - Dec)
Sample Data
|Table 1|
|ColDate | value|
|1-nov-2016 | 6|
Expected Output
ColDate | value | month | monthnumber
1-nov-2016 | 6 | Nov | 11
1-nov-2016 | 0 | Dec |12
..... 0 for all other months except Nov
I used cross join between table 1 and table 2 but it gives output as
1-nov-2016 | 6 | Nov | 11
1-nov-2016 | 6 | Dec |12
..... 6 for all other months though should be 0 except Nov.
How do i do that ?
Try this,
DECLARE #TB1 TABLE (COLDATE VARCHAR(20),VALUE INT)
INSERT INTO #TB1
SELECT '1-NOV-2016',6
DECLARE #TB2 TABLE(MONTH VARCHAR(10),MONTHNUMBER INT)
INSERT INTO #TB2
SELECT 'NOV',11
UNION ALL
SELECT 'DEC',12
SELECT COLDATE
,CASE WHEN MONTHNUMBER=11 THEN VALUE ELSE 0 END VALUE
,MONTH
,MONTHNUMBER
FROM #TB1
CROSS JOIN #TB2
Result:

SQL - how do I generate rows for each month based on date ranges in existing dataset?

assume I have a dataset:
rowID | dateStart | dateEnd | Year | Month
121 | 2013-10-03 | 2013-12-03 | NULL | NULL
143 | 2013-12-11 | 2014-03-11 | NULL | NULL
322 | 2014-01-02 | 2014-02-11 | NULL | NULL
And I want sql to generate the following datasource based on the dateStart and the dateEnd. Note the year and month grouping.
rowID | dateStart | dateEnd | Year | Month
121 | 2013-10-03 | 2013-12-03 | 2013 | 10
121 | 2013-10-03 | 2013-12-03 | 2013 | 11
121 | 2013-10-03 | 2013-12-03 | 2013 | 12
143 | 2013-12-11 | 2014-03-11 | 2013 | 12
143 | 2013-12-11 | 2014-03-11 | 2014 | 1
143 | 2013-12-11 | 2014-03-11 | 2014 | 2
143 | 2013-12-11 | 2014-03-11 | 2014 | 3
322 | 2014-01-02 | 2014-02-11 | 2014 | 1
322 | 2014-01-02 | 2014-02-11 | 2014 | 2
I'm having a hard time wrapping my head around this one. Any ideas?
I find it easiest to approach these problems by creating a list of integers and then using that to increment the dates. Here is an example:
with nums as (
select 0 as n
union all
select n + 1 as n
from nums
where n < 11
)
select rowid, datestart, dateend,
year(dateadd(month, n.n, datestart)) as yr,
month(dateadd(month, n.n, datestart)) as mon
from table t join
nums n
on dateadd(month, n.n - 1, datestart) <= dateend;
First, create a tabled-valued function that takes the 2 dates and returns the year and month as a table:
create function dbo.YearMonths(#StartDate DateTime, #EndDate DateTime)
returns #YearMonths table
([Year] int,
[Month] int)
as
begin
set #EndDate = DATEADD(month, 1, #EndDate)
while (#StartDate < #EndDate)
begin
insert into #YearMonths
select YEAR(#StartDate), MONTH(#StartDate)
set #StartDate = DATEADD(month, 1, #StartDate)
end
return
end
As an example the following:
select *
from dbo.YearMonths('1/1/2014', '5/1/2014')
returns:
Then you would join to it like this to get what you wanted:
select m.*, ym.Year, ym.Month
from myTable m
cross apply dbo.YearMonths(dateStart, dateEnd) ym
Try this:
declare #months table(mth int)
insert into #months values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
declare #calendar table(yr int,mth int)
insert into #calendar
select distinct year(datestart),mth
from tbl cross join #months
union
select distinct year(dateend),mth
from tbl cross join #months
select t.rowID, t.datestart, t.dateend, y.yr [Year], y.mth [Month]
from
yourtable t
inner join #calendar y on year(datestart) = yr or year(dateend) = yr
where
(mth >= month(datestart) and mth <= month(dateend) and year(datestart) = year(dateend))
or
(year(datestart) < year(dateend))
and
(year(datestart) = yr and mth >= month(datestart) --All months of start year
or
(year(dateend) = yr and mth <= month(dateend))) -- All months of end year
order by t.rowID, [Year],[Month]
We create a 'Calendar table' which lists all the month and year combinations present in the source table. Then, we join the source table to the calendar table based on the year, and filter as required.

How do i can show forecast years data from row into column?

Suppose if Item-A's Sale in 2013 is 100 Quantity and I'm expecting 10% of sales growth in next year i.e. in 2014
--------------------
ITEM | YEAR | QTY |
--------------------
ITM-A| 2013 | 100 |
ITM-B| 2013 | 200 |
--------------------
if I want to forecast sale data for up to year 2015
------------------------------
Item | 2013 | 2014 | 2015 |
------------------------------
Item-A | 100 | 110 | 121 |--each year qty incremented by 10% of its
Item-B | 200 | 220 | 242 |--previous year qty
------------------------------
try this,you have to use dynamic sql
Declare #toyear int=2016
Declare #forcast int=10
Declare #t table (ITEM varchar(50), years int, qty int)
insert into #t
select 'TM-A' ITEM , 2013 years, 100 qty
union all
select 'TM-B' ITEM , 2013 years, 200 qty
;with CTE1 as
(
select * from #t
union all
select b.ITEM,b.years+1,b.qty+((#forcast*b.qty)/100) from #t a
inner join cte1 b on a.ITEM=b.ITEM
and b.years<#toyear
)
select * from
(select * from cte1 )t4
pivot(min(qty) for years in([2013],[2014],[2015],[2016]))pvt
Try this:
select item,
qty as '2013',
round(qty*1.1) as '2014',
round(qty*1.21) as '2015'
from sale;
A dynamic query using stored procedure
DELIMITER $$
create procedure p (IN end INT(10))
BEGIN
declare start int;
declare fact FLOAT;
SET fact = 1.1;
SELECT year into start FROM sale limit 1;
SET #QUERY1 = CONCAT("SELECT ITEM, QTY AS '",start,"'");
WHILE start < end DO
SET start = start + 1;
SET #QUERY1 = CONCAT(#QUERY1," ,qty*",fact," as '", start,"'");
SET fact = fact *1.1;
END WHILE;
SET #QUERY1 = CONCAT(#QUERY1," from sale");
PREPARE stmt FROM #QUERY1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
Output:
mysql> call p(2016);
+-------+------+-------+--------+---------+
| ITEM | 2013 | 2014 | 2015 | 2016 |
+-------+------+-------+--------+---------+
| itemA | 100 | 110.0 | 121.00 | 133.100 |
| itemB | 200 | 220.0 | 242.00 | 266.200 |
+-------+------+-------+--------+---------+
2 rows in set (0.00 sec)
Check this question:
Pass a function return to another in the same row
Your function is simply the multiplication by 1.1

Resources