Related
I have the following code that loops through a table with unique model numbers and creates a new table that contains, for each model numbers, a row based on the year and week number. How can I translate this so it doesn't use a cursor?
DECLARE #current_model varchar(50);
--declare a cursor that iterates through model numbers in ItemInformation table
DECLARE model_cursor CURSOR FOR
SELECT model from ItemInformation
--start the cursor
OPEN model_cursor
--get the next (first value)
FETCH NEXT FROM model_cursor INTO #current_model;
DECLARE #year_counter SMALLINT;
DECLARE #week_counter TINYINT;
WHILE (##FETCH_STATUS = 0) --fetch status returns the status of the last cursor, if 0 then there is a next value (FETCH statement was successful)
BEGIN
SET #year_counter = 2019;
WHILE (#year_counter <= Datepart(year, Getdate() - 1) + 2)
BEGIN
SET #week_counter = 1;
WHILE (#week_counter <= 52)
BEGIN
INSERT INTO dbo.ModelCalendar(
model,
sales_year,
sales_week
)
VALUES(
#current_model,
#year_counter,
#week_counter
)
SET #week_counter = #week_counter + 1
END
SET #year_counter = #year_counter + 1
END
FETCH NEXT FROM model_cursor INTO #current_model
END;
CLOSE model_cursor;
DEALLOCATE model_cursor;
If ItemInformation contains the following table:
model,invoice
a,4.99
b,9.99
c,1.99
d,8.99
then the expected output is:
model,sales_year,sales_week
A,2019,1
A,2019,2
A,2019,3
...
A,2019,52
A,2020,1
A,2020,2
A,2020,3
...
A,2020,51
A,2020,52
A,2020,53 (this is 53 because 2020 is leap year and has 53 weeks)
A,2021,1
A,2021,2
...
A,2022,1
A,2022,2
...
A,2022,52
B,2019,1
B,2019,2
...
D, 2022,52
Using CTE's you can get all combinations of weeks and years within the range required. Then join your data table on.
declare #Test table (model varchar(1), invoice varchar(4));
insert into #Test (model, invoice)
values
('a', '4.99'),
('b', '9.99'),
('c', '1.99'),
('d', '8.99');
with Week_CTE as (
select 1 as WeekNo
union all
select 1 + WeekNo
from Week_CTE
where WeekNo < 53
), Year_CTE as (
select 2019 YearNo
union all
select 1 + YearNo
from Year_CTE
where YearNo <= datepart(year, current_timestamp)
)
select T.model, yr.YearNo, wk.WeekNo
from Week_CTE wk
cross join (
select YearNo
-- Find the last week of the year (52 or 53) -- might need to change the start day of the week for this to be correct
, datepart(week, dateadd(day, -1, dateadd(year, 1, '01 Jan ' + convert(varchar(4),YearNo)))) LastWeek
from Year_CTE yr
) yr
cross join (
-- Assuming only a single row per model is required, and the invoice column can be ignored
select model
from #Test
group by model
) T
where wk.WeekNo <= yr.LastWeek
order by yr.YearNo, wk.WeekNo;
As you have advised that using a recursive CTE is not an option, you can try using a CTE without recursion:
with T(N) as (
select X.N
from (values (0),(0),(0),(0),(0),(0),(0),(0)) X(N)
), W(N) as (
select top (53) row_number() over (order by ##version) as N
from T T1
cross join T T2
), Y(N) as (
-- Upper limit on number of years
select top (12) 2018 + row_number() over (order by ##version) AS N
from T T1
cross join T T2
)
select W.N as WeekNo, Y.N YearNo, T.model
from W
cross join (
select N
-- Find the last week of the year (52 or 53) -- might need to change the start day of the week for this to be correct
, datepart(week, dateadd(day, -1, dateadd(year, 1, '01 Jan ' + convert(varchar(4),N)))) LastWeek
from Y
) Y
cross join (
-- Assuming only a single row per model is required, and the invoice column can be ignored
select model
from #Test
group by model
) T
-- Filter to required number of years.
where Y.N <= datepart(year, current_timestamp) + 1
and W.N <= Y.LastWeek
order by Y.N, W.N, T.model;
Note: If you setup your sample data in future with the DDL/DML as shown here you will greatly assist people attempting to answer.
I don't like to see a loop solution where a set solution can be found. So here goes Take II with no CTE, no values and no row_number() (the table variable is just to simulate your data so not part of the actual solution):
declare #Test table (model varchar(1), invoice varchar(4));
insert into #Test (model, invoice)
values
('a', '4.99'),
('b', '9.99'),
('c', '1.99'),
('d', '8.99');
select Y.N + 2019 YearNumber, W.WeekNumber, T.Model
from (
-- Cross join 5 * 10, then filter to 52/53 as required
select W1.N * 10 + W2.N + 1 WeekNumber
from (
select 0 N
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
) W1
cross join (
select 0 N
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9
) W2
) W
-- Cross join number of years required, just ensure its more than will ever be needed then filter back
cross join (
select 0 N
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9
) Y
cross join (
-- Assuming only a single row per model is required, and the invoice column can be ignored
select model
from #Test
group by model
) T
-- Some filter to restrict the years
where Y.N <= 3
-- Some filter to restrict the weeks
and W.WeekNumber <= 53
order by YearNumber, WeekNumber;
I created a table to temporary calendar table containing all the weeks and years. To account for leap years, I took the last 7 days of a year and got the ISO week for each day. To know how many weeks are in a year, I put these values into another temp table and took the max value of it. Azure Synapse doesn't support multiple values in one insert so it looks a lot longer than it should be. I also have to declare each as variable since Synapse can only insert literal or variable. I then cross-joined with my ItemInformation table.
CREATE TABLE #temp_dates
(
year SMALLINT,
week TINYINT
);
CREATE TABLE #temp_weeks
(
week_num TINYINT
);
DECLARE #year_counter SMALLINT
SET #year_counter = 2019
DECLARE #week_counter TINYINT
WHILE ( #year_counter <= Datepart(year, Getdate() - 1) + 2 )
BEGIN
SET #week_counter = 1;
DECLARE #day_1 TINYINT
SET #day_1 = Datepart(isowk, Concat('12-25-', #year_counter))
DECLARE #day_2 TINYINT
SET #day_2 = Datepart(isowk, Concat('12-26-', #year_counter))
DECLARE #day_3 TINYINT
SET #day_3 = Datepart(isowk, Concat('12-27-', #year_counter))
DECLARE #day_4 TINYINT
SET #day_4 = Datepart(isowk, Concat('12-28-', #year_counter))
DECLARE #day_5 TINYINT
SET #day_5 = Datepart(isowk, Concat('12-29-', #year_counter))
DECLARE #day_6 TINYINT
SET #day_6 = Datepart(isowk, Concat('12-30-', #year_counter))
DECLARE #day_7 TINYINT
SET #day_7 = Datepart(isowk, Concat('12-31-', #year_counter))
TRUNCATE TABLE #temp_weeks
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_1)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_2)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_3)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_4)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_5)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_6)
INSERT INTO #temp_weeks
(week_num)
VALUES (#day_7)
DECLARE #max_week TINYINT
SET #max_week = (SELECT Max(week_num)
FROM #temp_weeks)
WHILE ( #week_counter <= #max_week )
BEGIN
INSERT INTO #temp_dates
(year,
week)
VALUES ( #year_counter,
#week_counter )
SET #week_counter = #week_counter + 1
END
SET #year_counter = #year_counter + 1
END
DROP TABLE #temp_weeks;
SELECT i.model,
d.year,
d.week
FROM dbo.iteminformation i
CROSS JOIN #temp_dates d
ORDER BY model,
year,
week
DROP TABLE #temp_dates
I cant create view with declare.
i even tried to create procedure but than i found that i cant create view with procedure. and i think same will be for function. only thing i can think of is to avoid declare. How can I find the way around? i need to have view table (in order to be able to see them in power bi in the future, i cant see it from stored procedure in it)
declare #T as table (
Name nvarchar(100)
, OBJECTID varchar(50)
, started_working datetime
,STOPFROM datetime
,STARTDATE datetime
,STOPDATE datetime
,MODIFIEDDATETIME datetime
,START_STOP int
,STARTDESCRIPTION nvarchar(300)
,STOPDESCRIPTION nvarchar(300)
,wattage nvarchar (50)
,purpose nvarchar(300)
,location nvarchar(300)
,finished_working datetime
,oldDiff int
)
insert into #T
select
NAME
,OBJECTID
,STOPTO
,STOPFROM
,STARTDATE
,STOPDATE
,MODIFIEDDATETIME
,START_STOP
,STARTDESCRIPTION
,STOPDESCRIPTION
,wattage
,purpose
,location
,next_stopfrom
,diff
FROM [MicrosoftDynamicsAX].[dbo].[mroobjectengineworkinghours]
;with rcte as (
select
*, started_working2 = started_working
, next_date = cast(dateadd(dd, 1, started_working) as date), 1 step
from
#T
union all
select
Name,OBJECTID, started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION
,STOPDESCRIPTION,wattage
,purpose
,location, finished_working,oldDiff
, cast(next_date as datetime)
, dateadd(dd, 1, next_date), step + 1
from
rcte
where
next_date < finished_working
)
select
Name,OBJECTID, started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION
,STOPDESCRIPTION,wattage
,purpose
,location,oldDiff, started_working2, finished_working
, right(replace(str(diff / 60), ' ', 0), 2) + ':' + right(replace(str(diff % 60), ' ', 0), 2) hours_worked
from (
select
Name,OBJECTID, started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION
,STOPDESCRIPTION,wattage
,purpose
,location,oldDiff
, case
when step = 1 then started_working
else started_working2
end started_working2
, case
when step = max(step) over (partition by Name, started_working)
then finished_working else next_date
end finished_working
from
rcte
) t
cross apply (select datediff(mi, started_working2, finished_working) diff) ca
OPTION (MAXRECURSION 0);
I agree with Sean Lange.
Why not in your cte simply call the table directly?
Such as:
;with rcte as (
select *
, started_working2 = started_working
, next_date = cast(dateadd(dd, 1, started_working) as date)
, 1 step
from [MicrosoftDynamicsAX].[dbo].[mroobjectengineworkinghours] ...
I have 3 columns in table which are Id(int) , Value(int) and Time(datetime). I want query that get data(s) for 1st 10 mins then 2nd set of 10 mins and continued on..
Example of data from the table
Screenshot of data
I tried using this query but it display nothing
SELECT sensor_Id
,sensor_Value
,sensor_Timestamp
FROM TABLE
WHERE DATEDIFF(MINUTE, sensor_Timestamp, GETDATE()) <= 10
Your query is fine, if you want to show the values from the 10 minutes immediately before the time the query was run.
If you want some specific 10-minute interval, you need to specify that (by passing that date & time in place of getdate() or by using between with a start and end time.
For example:
SELECT sensor_Id ,sensor_Value ,sensor_Timestamp
FROM TABLE where sensor_Timestamp between '2016-10-10 15:50' and '2016-10-10 16:00'
Please try this (I am trying to create start and end date variables with minutes divisible by 10)
declare #current_time datetime = getdate()
declare #total_minutes int = datediff(minute, 0, #current_time)
declare #add_subtract_minutes int = #total_minutes % 10
declare #start_date datetime = dateadd(minute, #total_minutes - #add_subtract_minutes, 0)
declare #end_date datetime = dateadd(minute, #total_minutes + (10 - #add_subtract_minutes), 0)
SELECT sensor_Id
,sensor_Value
,sensor_Timestamp
FROM TABLE
WHERE sensor_Timestamp between #start_date and #end_date
Test Snapshot-
This might not be the exact solution, you can try something like this:
Declare #startdatetime datetime= '2016-10-10 15:49:15.000'
Declare #executeForThisNumber int = 3 -- for 3 intervals of 10 mins after #startdatetime
While #executeForThisNumber > 0
begin
declare #cmd varchar(max) = 'Select * from table
Where sensor_TimeStamp > ''' + convert(varchar(40), DATEADD(mi,-10,#startdatetime), 121) + ''' AND sensor_TimeStamp <= ''' + convert(varchar(40), #startdatetime, 121) + ''''
EXEC (#cmd)
set #startdatetime = convert(varchar(40), DATEADD(mi,10,#startdatetime), 121)
set #executeForThisNumber = #executeForThisNumber - 1
end
Below query will give you desired result
SELECT sensor_Id, sensor_Value, CONVERT(VARCHAR(10), CONVERT(DATETIME, sensor_Timestamp, 0), 101) + CONVERT(VARCHAR(4),CONVERT(DATETIME, sensor_Timestamp, 0), 108) as sensorTimestamp
FROM TABLE
group by sensor_Id, sensor_Value, sensorTimestamp
I have truncated the second digit of minute to put aggregate function on it.
Here you go, this should get you going. You just need to format the datetime values to truncate the last minute digit.
-- SET UP TEST DATA
IF OBJECT_ID('tempdb..#SensorData', 'U') IS NOT NULL DROP TABLE #SensorData;
CREATE TABLE #SensorData (sendor_ID int, sensor_Value int, sensor_Timestamp DATETIME);
INSERT #SensorData (sendor_ID, sensor_Value, sensor_Timestamp)
SELECT A.sendor_ID, A.sensor_Value, A.sensor_Timestamp
FROM (
SELECT * FROM #SensorData WHERE 1=2
UNION ALL SELECT 1, 0001, '06/18/2020 01:01'
UNION ALL SELECT 1, 0002, '06/18/2020 01:02'
UNION ALL SELECT 1, 0003, '06/18/2020 01:03'
UNION ALL SELECT 1, 0005, '06/18/2020 01:05'
UNION ALL SELECT 1, 0008, '06/18/2020 01:08'
UNION ALL SELECT 1, 1013, '06/18/2020 01:13'
UNION ALL SELECT 1, 1016, '06/18/2020 01:16'
UNION ALL SELECT 1, 2021, '06/18/2020 01:21'
UNION ALL SELECT 1, 2027, '06/18/2020 01:27'
UNION ALL SELECT 1, 3032, '06/18/2020 01:32'
UNION ALL SELECT 1, 3036, '06/18/2020 01:36'
UNION ALL SELECT 1, 4041, '06/18/2020 01:41'
UNION ALL SELECT 1, 4047, '06/18/2020 01:47'
UNION ALL SELECT 1, 5054, '06/18/2020 01:54'
UNION ALL SELECT 1, 5059, '06/18/2020 01:59'
UNION ALL SELECT 1, 20001, '06/18/2020 02:01'
UNION ALL SELECT 1, 20002, '06/18/2020 02:02'
) A
-- SIMPLY RETURN THE DATA AND CHANGE TIMES TO 10 MINUE INTERVALS
SELECT A.sendor_ID
,A.sensor_Value
,(CONVERT(char(15), A.sensor_Timestamp, 121)+'0')
FROM #SensorData A
-- AGGREGATE IN 10 MINUTE INTERVALS
SELECT A.sendor_ID
,COUNT(*) AS LogInstances
,SUM(A.sensor_Value) AS Total_sensor_Value
,(CONVERT(char(15), A.sensor_Timestamp, 121)+'0') AS sensor_Timestamp_10min_Intervals
FROM #SensorData A
GROUP BY A.sendor_ID
,(CONVERT(char(15), A.sensor_Timestamp, 121)+'0')
ORDER BY A.sendor_ID
,(CONVERT(char(15), A.sensor_Timestamp, 121)+'0')
The result of DATEDIFF is a number of days ( https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff )
I think you can do something like that (not tested) :
SELECT sensor_Id, sensor_Value, sensor_Timestamp FROM Table WHERE sensor_Timestamp > DATE_SUB(now(), INTERVAL 10 MINUTE)
These are my tables:
CREATE TABLE forgerock (id INT, [date] DATETIME, empcode INT,[file] VARCHAR);
INSERT INTO forgerock
VALUES
(1, '2015-12-31 01:20:02', 56, 'abc1'),
(2, '2016-01-01 01:20:02', 58, 'abc2'),
(3, '2016-01-02 01:20:02', 46, 'abc3'),
(4, '2016-01-03 01:20:02', 16, 'abc4'),
(5, '2016-01-04 01:20:02', 36, 'abc5');
CREATE TABLE forge (empcode INT, [user_name] VARCHAR);
INSERT INTO forge
VALUES
(56, 'ram'),
(58, 'ram1'),
(46, 'ram2'),
(16, 'ram3'),
(36, 'ram4');
I am trying to print the file name and user_name from the tables with respect to current date and the day before the current date.
I tried the query:
ResultSet resultset = statement.executeQuery("select file from forgerock where '"+date+"' >= CURRENT_DATE('"+date+"', INTERVAL 1 DAY);") ;
but I got the exception:
Incorrect syntax near the keyword 'CURRENT_DATE'.
IF OBJECT_ID('dbo.forgerock', 'U') IS NOT NULL
DROP TABLE dbo.forgerock
CREATE TABLE dbo.forgerock (id INT PRIMARY KEY, [date] DATETIME, empcode INT,[file] VARCHAR(10));
INSERT INTO dbo.forgerock
VALUES
(1, '2015-12-31 01:20:02', 56, 'abc1'),
(2, '2016-01-01 01:20:02', 58, 'abc2'),
(3, '2016-01-02 01:20:02', 46, 'abc3'),
(4, '2016-01-03 01:20:02', 16, 'abc4'),
(5, '2016-01-04 01:20:02', 36, 'abc5');
IF OBJECT_ID('dbo.forge', 'U') IS NOT NULL
DROP TABLE dbo.forge
CREATE TABLE dbo.forge (empcode INT PRIMARY KEY, [user_name] VARCHAR(10));
INSERT INTO dbo.forge
VALUES (56, 'ram'),(58, 'ram1'),(46, 'ram2'),(16, 'ram3'),(36, 'ram4')
DECLARE #dt DATETIME = FLOOR(CAST(GETDATE() AS FLOAT))
SELECT *
FROM dbo.forge
WHERE empcode IN (
SELECT f.empcode
FROM dbo.forgerock f
WHERE f.[date] BETWEEN DATEADD(DAY, -1, #dt) AND #dt
)
output -
empcode user_name
----------- ----------
16 ram3
SELECT fr.file, f.user_name
FROM forgerock fr inner join forge f on fr.empcode = f.empcode
WHERE fr.date >= DATE_ADD(NOW(), INTERVAL -1 DAY)
You can use datediff to get the difference between two dates.
Try this :
ResultSet resultset = statement.executeQuery("select file from forgerock where DATEDIFF(day, GETDATE(), '" + date + "') >= 1") ;
To test the query use this one :
SELECT * FROM forgerock WHERE DATEDIFF(day, GETDATE(), #date) >= 1;
Just replace the #date with the value you want, for example '2016-01-02'
Use this filter:
SELECT [file]
FROM forgerock
WHERE [date] >= DATEADD(DAY, DATEDIFF(DAY,0,GETDATE()-1),0)
The DATEADD expression above will always return 12:00am yesterday morning, allowing your query to only return records from yesterday or today.
Bonus Tip: avoid using reserved keywords (such as file and date) as column or table names.
Since am using ms sql the code should be the following way
SELECT fr.file, f.user_name FROM forgerock fr inner join forge f on fr.empcode = f.empcodewhere [date] >= DATEADD(DAY, DATEDIFF(DAY,0,GETDATE()-1),0)
which will result in printing the two tables file from forgerock and user_name from forge
You have to try following query:-
SELECT fr.file, f.user_name
FROM forgerock fr inner join forge f on fr.empcode = f.empcode
AND `date' >= (DATE_ADD(`date`, INTERVAL 1 day))
I'm attempting to have a column return the sum of a weeks worth of hours from a time unit column. However, It's only returning a null value, and I'm not certain why. Could anyone help? Thank you in advance!
SELECT
[Employee Name],
[Week1] = ISNULL(SUM(CASE WHEN tdate BETWEEN DATEADD(Week,-3,Timesheetdate) AND DATEADD(DAY,-1,DATEADD(WEEK,-2,Timesheetdate)) THEN (Units) END),0 )
[Week2] = ISNULL(SUM(CASE WHEN tdate BETWEEN DATEADD(Week,-2,Timesheetdate) AND DATEADD(DAY,-1,DATEADD(WEEK,-1,Timesheetdate)) THEN (Units) END),0 )
From #Temp
LEFT JOIN TransTable ON TranTable.trankey = Timesheet.tkey
Group By
EmployeeName,
tdate,
tunits,
timesheetdate
DROP TABLE #Temp
CREATE TABLE #Temp ( [EmployeeName] varchar(100), Timesheetdate datetime , Units int , tdate datetime)
insert into #Temp values ( 1, '2015-03-02',1,'2015-03-02')
insert into #Temp values ( 1, '2015-02-02',2,'2015-02-02')
insert into #Temp values ( 1, '2015-02-02',3,'2015-02-02')
insert into #Temp values ( 1, '2015-02-27',4,'2015-02-02')
insert into #Temp values ( 1, '2015-03-24',5,'2015-02-02')
insert into #Temp values ( 1, '2015-03-02',1,'2015-02-15')
insert into #Temp values ( 1, '2015-02-02',2,'2015-02-17')
insert into #Temp values ( 1, '2015-02-02',3,'2015-02-18')
insert into #Temp values ( 1, '2015-02-27',4,'2015-02-20')
insert into #Temp values ( 1, '2015-03-24',5,'2015-02-14')
insert into #Temp values ( 1, '2015-03-02',1,'2015-02-28')
insert into #Temp values ( 1, '2015-02-02',2,'2015-02-27')
insert into #Temp values ( 1, '2015-02-02',3,'2015-02-26')
insert into #Temp values ( 1, '2015-02-27',4,'2015-02-25')
insert into #Temp values ( 1, '2015-03-24',5,'2015-02-24')
insert into #Temp values ( 1, '2015-03-02',1,'2015-02-21')
insert into #Temp values ( 1, '2015-02-02',2,'2015-02-20')
insert into #Temp values ( 1, '2015-02-02',3,'2015-02-18')
insert into #Temp values ( 1, '2015-02-27',4,'2015-02-20')
insert into #Temp values ( 1, '2015-03-24',5,'2015-02-18')
SELECT
EmployeeName,
[Week1] = ISNULL(SUM(CASE WHEN tdate BETWEEN DATEADD(Week,-3,Timesheetdate) AND DATEADD(DAY,-1,DATEADD(WEEK,-2,Timesheetdate)) THEN (Units) ELSE 0 END),0 ),
[Week2] = ISNULL(SUM(CASE WHEN tdate BETWEEN DATEADD(Week,-2,Timesheetdate) AND DATEADD(DAY,-1,DATEADD(WEEK,-1,Timesheetdate)) THEN (Units) ELSE 0 END),0 )
From #Temp
GROUP BY EmployeeName
It seems to work just fine, all I did I've added ELSE 0 ( which was not necesary as it works just fine without it too).
Take a better look at your dates. Maybe it should return null