altering a table using sql - mysql

I have this table
**Original Table**
year month duration amount per month
2012 5 3 2000
and I want to get this
**Result table**
year month duration amount per month
2012 5 1 2000
2012 6 1 2000
2012 7 1 2000
Note how the duration of a project (this is a project) is 3 and the "amount per month" is 2000, so I added two more rows to show that the next months (6 and 7) will have an "amount per month" as well. How do I do that with sql/tsql?

try this for SQL SERVER, i included my test temp table:
declare #temp as table
(
[year] int
, [month] int
, [duration] int
, [amount] int
)
insert into #temp
(
[year]
, [month]
, [duration]
, [amount]
)
VALUES(
2012
,5
,3
,2000
)
SELECT
[year]
,[month] + n.number
,1
,[amount]
, '1' + SUBSTRING(CAST([duration] AS varchar(10)), 2, 1000) AS Items
FROM #temp
JOIN master..spt_values n
ON n.type = 'P'
AND n.number < CONVERT(int, [duration])

Please see the script below that may work for your requirement. I have also compensated for calender year and month increment. Please test and let me know.
DECLARE #temp AS TABLE([Year] INT,[Month] INT,Duration INT,Amount INT)
INSERT INTO #temp([year], [month], Duration, Amount)
VALUES (2011, 5, 3, 2000),(2012, 11, 3, 3000),(2013, 9, 12, 1000);
;WITH cte_datefix
AS (
SELECT [Year],
[Month],
Duration,
Amount,
CAST(CAST([Year] AS VARCHAR(4)) + RIGHT('00' + CAST([Month] AS VARCHAR(2)), 2) + '01' AS DATE) AS [Date]
FROM #temp
),
cte_Reslut
AS (SELECT [Year],
[Month],
Duration,
Amount,
[Date],
1 AS Months
FROM cte_datefix
UNION ALL
SELECT t.[Year],
t.[Month],
t.Duration,
t.Amount,
DATEADD(M, Months, t.[Date]) AS [Date],
cr.Months + 1 AS Months
FROM cte_Reslut AS cr
INNER JOIN cte_datefix AS t
ON t.[Year] = cr.[Year]
WHERE cr.Months < cr.Duration
)
SELECT YEAR([Date]) AS [Year],
MONTH([Date]) AS [Month],
1 AS Duration,
Amount
FROM cte_Reslut
ORDER BY [Date]

For those that are wondering how to increment the year if needed, here is an example building on Suing response (really easy, just include two case statements):
select
2012 as [year]
,11 as [month]
,5 as [duration]
,2000 as [amount]
into #temp
select * from #temp
SELECT
case
when [month] + n.number > 12
then [year] + 1
else [year]
end as [year]
,case
when [month] + n.number > 12
then [month] + n.number - 12
else [month] + n.number
end as newYear
,1 as newDuration
,[amount]
, '1' + SUBSTRING(CAST([duration] AS varchar(10)), 2, 1000) AS Items
FROM #temp
JOIN master..spt_values n
ON n.type = 'P'
AND n.number < CONVERT(int, [duration])
drop table #temp

Related

How to conver this SQL server Function into a CTE in snowflake

I have two functions in SQL server that i'm trying to recreate in snowflake. i want to make it a CTE instead as i'm having many issues with it being a function (very picky about date parameters passed through)
I'm not quite thinking of it in the right way. So we pass two paramters through, a date and an int. and the function returns an INT value for us. I'm kind of "stuck".
--Function 1: Straight from SQL server
ALTER FUNCTION [dbo].[cfn_GetShiftIDFromDateTime] (
#dateTime datetime,
#shiftCalendarID int
)
RETURNS int
AS
BEGIN
DECLARE
#time time = CONVERT( time, #dateTime ),
#curDay int,
#prvDay int,
#shiftID int;
SELECT TOP 1
#shiftCalendarID = ID,
#curDay = DATEDIFF( dd, BeginDate, #dateTime ) % PeriodInDays + 1,
#prvDay = ( #curDay + PeriodInDays - 2 ) % PeriodInDays + 1
FROM ShiftCalendar
WHERE ID = #shiftCalendarID
OR ( #shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= #dateTime )
ORDER BY BeginDate DESC;
SELECT #shiftID = ID
FROM Shift
WHERE ShiftCalendarID = #shiftCalendarID
AND ( ( FromDay = #curDay AND FromTimeOfDay <= #time AND TillTimeOfDay > #time )
OR ( FromDay = #curDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= #time )
OR ( FromDay = #prvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > #time )
);
RETURN #shiftID;
END
--GO
I had help from a user writing this and was able to get this function written in snowflake and seems to be working properly. here it is below
--Function 1 -- Snowflake syntax, currently working
CREATE OR REPLACE FUNCTION DB_BI_DEV.RAW_CPMS_AAR.cfn_GetShiftIDFromDateTime (dateTime TIMESTAMP_NTZ(9), shiftCalendarID int)
RETURNS table (shiftID int)
AS
$$
WITH T0 (ShiftCalendarID, CurDay, PrvDay)
AS (
SELECT TOP 1
ID AS ShiftCalendarID,
DATEDIFF( day, BeginDate, dateTime ) % PeriodInDays + 1 AS CurDay,
( CurDay + PeriodInDays - 2 ) % PeriodInDays + 1 AS PrvDay
FROM RAW_CPMS_AAR.ShiftCalendar
WHERE ID = shiftCalendarID
OR ( shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= dateTime )
ORDER BY BeginDate DESC
),
T1 (TimeValue)
AS (
SELECT TIME_FROM_PARTS(
EXTRACT(HOUR FROM dateTime),
EXTRACT(MINUTE FROM dateTime),
EXTRACT(SECOND FROM dateTime))
)
SELECT ID as shiftID
FROM RAW_CPMS_AAR.Shift, T0, T1
WHERE Shift.ShiftCalendarID = T0.ShiftCalendarID
AND ( ( FromDay = T0.CurDay AND FromTimeOfDay <= T1.TimeValue AND TillTimeOfDay > T1.TimeValue )
OR ( FromDay = T0.CurDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= T1.TimeValue )
OR ( FromDay = T0.PrvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > T1.TimeValue )
)
$$
;
here is function 2:
--Function 2: Straight from SQL server
ALTER FUNCTION [dbo].[cfn_GetEquipmentShiftCalendarID] ( #equipmentID int, #date datetime )
RETURNS int
AS
BEGIN
IF #date IS NULL SET #date = GETDATE();
DECLARE
#shiftCalendarID int,
#endDate date;
WITH cte ( ID, ParentEquipmentID, ShiftCalendarEntityNumber ) AS (
SELECT ID, ParentEquipmentID, ShiftCalendarEntityNumber
FROM Equipment
WHERE ID = #equipmentID
UNION ALL
SELECT p.ID, p.ParentEquipmentID, p.ShiftCalendarEntityNumber
FROM cte
INNER JOIN Equipment p ON p.ID = cte.ParentEquipmentID AND cte.ShiftCalendarEntityNumber IS NULL
)
SELECT TOP 1 #shiftCalendarID = sc.ID, #endDate = sc.EndDate
FROM cte
INNER JOIN ShiftCalendar sc ON sc.EntityNumber = cte.ShiftCalendarEntityNumber
WHERE sc.BeginDate <= #date
ORDER BY
CASE WHEN EndDate IS NULL OR EndDate > #date THEN 1 ELSE 2 END, -- Prio on date range
sc.BeginDate DESC;
IF #shiftCalendarID IS NULL
BEGIN
-- Default to the last created calendar we find that started before the given time
SELECT TOP 1 #shiftCalendarID = ID
FROM ShiftCalendar
WHERE BeginDate < #date
ORDER BY BeginDate DESC;
END;
RETURN #shiftCalendarID; -- CASE WHEN #endDate IS NULL OR #endDate > #date THEN #shiftCalendarID END; -- Return NULL when no matching date range found?
END
GO
This one I was able to rewrite in snowflake but the if statement isnt working. I am not sure if snowflake function can use an if statement.
ALTER FUNCTION [dbo].[cfn_GetShiftIDFromDateTime] (
#dateTime datetime,
#shiftCalendarID int
)
RETURNS int
AS
BEGIN
DECLARE
#time time = CONVERT( time, #dateTime ),
#curDay int,
#prvDay int,
#shiftID int;
SELECT TOP 1
#shiftCalendarID = ID,
#curDay = DATEDIFF( dd, BeginDate, #dateTime ) % PeriodInDays + 1,
#prvDay = ( #curDay + PeriodInDays - 2 ) % PeriodInDays + 1
FROM ShiftCalendar
WHERE ID = #shiftCalendarID
OR ( #shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= #dateTime )
ORDER BY BeginDate DESC;
SELECT #shiftID = ID
FROM Shift
WHERE ShiftCalendarID = #shiftCalendarID
AND ( ( FromDay = #curDay AND FromTimeOfDay <= #time AND TillTimeOfDay > #time )
OR ( FromDay = #curDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= #time )
OR ( FromDay = #prvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > #time )
);
RETURN #shiftID;
END
--GO
so how are these functions used? i have a view which i was able to recreate in snowflake, but is missing the part that calls the function.
ALTER VIEW [proj].[pvw_PowerBI_ActualUnits]
SELECT
e.Name AS ProductionUnit,
temp.DateTime AS DateTime,
s.Reference AS Shift,
CONVERT(TIME, temp.DateTime) AS Time,
CONVERT(DATE, temp.DateTime - ISNULL((SELECT CAST(MIN(s_first.FromTimeOfDay) AS DateTime) FROM [Shift] s_first WHERE s_first.FromDay = s.FromDay AND s_first.ShiftCalendarID = s.ShiftCalendarID), CAST('6:00' AS DateTime))) AS ProductionDate,
'Actual Units' AS ScrapReason,
temp.ScrapQuantity AS ScrapQuantity,
'Auto Registered' AS RegistrationType,
s.ID
FROM
(SELECT
vl.EquipmentID AS ProductionUnit,
DATEADD(MINUTE, 30 * (DATEPART(MINUTE, vl.BeginTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, vl.BeginTime), 0)) AS DateTime,
SUM(vl.Quantity) AS ScrapQuantity
FROM oee.ValueLog vl WITH (NOLOCK)
INNER JOIN KPIInstance ki ON ki.ID = vl.KPIInstanceID AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY DATEADD(MINUTE, 30 * (DATEPART(MINUTE, vl.BeginTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, vl.BeginTime), 0)), vl.EquipmentID) temp
INNER JOIN Equipment e ON e.ID = temp.ProductionUnit
INNER JOIN Shift s ON s.ID = dbo.cfn_GetShiftIDFromDateTime(temp.DateTime, dbo.cfn_GetEquipmentShiftCalendarID(temp.ProductionUnit, temp.DateTime)) -- here is where the functions are called
i was able to rewrite this in snowflake for the most part minus calling the function.
SELECT
e.Name AS ProductionUnit,
temp.DateTime AS DateTime,
s.Reference AS Shift,
temp.DateTime::TIME AS Time,
--CONVERT(DATE, temp.DateTime - ISNULL((SELECT CAST(MIN(s_first.FromTimeOfDay) AS DateTime) FROM [Shift] s_first WHERE s_first.FromDay = s.FromDay AND s_first.ShiftCalendarID = s.ShiftCalendarID), CAST('6:00' AS DateTime))) AS ProductionDate,
IFNULL(dateadd(HOUR, - (HOUR(SELECT MIN(s_first.FromTimeOfDay)
FROM RAW_CPMS_AAR.Shift s_first WHERE s_first.FromDay = s.FromDay AND s_first.ShiftCalendarID = s.ShiftCalendarID)), temp.DateTime), (dateadd(HOUR, - 6, temp.DateTime))) AS ProductionDate ,
'Actual Units' AS ScrapReason,
temp.ScrapQuantity AS ScrapQuantity,
'Auto Registered' AS RegistrationType
FROM
(SELECT
vl.EquipmentID AS ProductionUnit,
DATEADD(MIN, 30 * (DATE_PART(MINUTE, vl.BeginTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, '0', vl.BeginTime), '0')) AS DateTime,
SUM(vl.Quantity) AS ScrapQuantity
FROM RAW_CPMS_AAR.ValueLog vl
INNER JOIN KPIInstance ki ON ki.ID = vl.KPIInstanceID AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY DATEADD(MIN, 30 * (DATE_PART(MINUTE, vl.BeginTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, '0', vl.BeginTime), '0')), vl.EquipmentID) as temp, shiftcalendar_cte, RAW_CPMS_AAR.Equipment e, RAW_CPMS_AAR.Shift s
WHERE e.ID = temp.ProductionUnit
Now i dont know if there is a better way to do this, maybe a cte is better. i know functions are not resource friendly, i'm simply trying to recreate this. open to any ideas or help.
ok, some small translations:
DATEADD(HOUR, DATEDIFF(HOUR, 0, vl.BeginTime), 0)
is truncating to the hour, so is the same as
date_trunc('HOUR', vl.BeginTime)
that dateadd thus is:
select column1
,date_trunc('hour', column1) as t_hour
,truncate(minute(column1)/30)*30
,timeadd('minute', truncate(minute(column1)/30)*30, date_trunc('hour', column1)) as datetime
from values
('2022-11-14 13:26:01'::timestamp_ntz),
('2022-11-14 12:34:01'::timestamp_ntz);
COLUMN1
T_HOUR
TRUNCATE(MINUTE(COLUMN1)/30)*30
DATETIME
2022-11-14 13:26:01.000
2022-11-14 13:00:00.000
0
2022-11-14 13:00:00.000
2022-11-14 12:34:01.000
2022-11-14 12:00:00.000
30
2022-11-14 12:30:00.000
So moving that sub-select that you alias as temp into a CTE, and get that "working"
WITH table_oee_valuelog(equipmentid, begintime, quantity, kpiinstanceid) as (
select * from values
(1, '2022-11-14 13:26:01'::timestamp_ntz, 10, 100),
(1, '2022-11-14 13:26:01'::timestamp_ntz, 11, 100),
(1, '2022-11-14 13:34:01'::timestamp_ntz, 12, 100)
), table_kpiinstance(id, kpidefinitionid) as (
select * from values
(100, 'COUNT-OUT:extra stuff')
)--, temp_sub_select as (
SELECT
vl.equipmentid as productionunit,
timeadd('minute', truncate(minute(vl.BeginTime)/30)*30, date_trunc('hour', vl.BeginTime)) as datetime,
SUM(vl.quantity) AS scrapquantity
FROM table_oee_valuelog as vl
INNER JOIN table_kpiinstance as ki
ON ki.ID = vl.KPIInstanceID
AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY 1,2
;)
PRODUCTIONUNIT
DATETIME
SCRAPQUANTITY
1
2022-11-14 13:00:00.000
21
1
2022-11-14 13:30:00.000
12
implementing cfn_GetEquipmentShiftCalendarID
so if we extend our table data a bit more we can take a first crack at cfn_GetEquipmentShiftCalendarID like:
WITH table_oee_valuelog(equipmentid, begintime, quantity, kpiinstanceid) as (
select * from values
(1, '2022-11-14 13:26:01'::timestamp_ntz, 10, 100),
(1, '2022-11-14 13:26:01'::timestamp_ntz, 11, 100),
(1, '2022-11-14 13:34:01'::timestamp_ntz, 12, 100)
), table_kpiinstance(id, kpidefinitionid) as (
select * from values
(100, 'COUNT-OUT:extra stuff')
), table_equipment(id, name, parentequipmentid, shiftcalendarentitynumber) as (
select * from values
(1,'equipment one', 2, null),
(2,'equipment two', null, 80),
(3,'equipment three', 4, 81),
(4,'equipment four', null, 82)
), table_shift(id, shiftcalendarid, reference) as (
select * from values
(1001, 9001, 'a')
), table_shiftcalendar(id, entitynumber, begindate, enddate) as (
select * from values
(699, 80, '2021-01-01'::date, '2021-12-31'::date),
(700, 80, '2022-01-01'::date, '2022-12-31'::date),
--(701, 81, '2022-02-01'::date, '2022-11-30'::date),
(702, 82, '2022-10-01'::date, '2022-11-15'::date)
), cte_GetEquipmentShiftCalendarID/*(id, shiftCalendarID)*/ as (
with recursive rec_cte (id, parentequipmentid, shiftcalendarentitynumber) as (
select
ID,
ParentEquipmentID,
ShiftCalendarEntityNumber
FROM table_equipment
UNION ALL
SELECT
r.ID,
p.ParentEquipmentID,
p.ShiftCalendarEntityNumber
FROM rec_cte as r
INNER JOIN table_equipment p
ON p.ID = r.ParentEquipmentID
AND r.ShiftCalendarEntityNumber IS NULL
)
select * from rec_cte as c
left join table_shiftcalendar as sc
on sc.entitynumber = c.ShiftCalendarEntityNumber
where shiftcalendarentitynumber is not null
qualify row_number() over (partition by c.id order by sc.begindate desc ) = 1
)
select * from cte_GetEquipmentShiftCalendarID;
This is missing the #date based filters and the catch all, as to product the "latest" all bit of equipment, cannot be done yet.
ID
PARENTEQUIPMENTID
SHIFTCALENDARENTITYNUMBER
ID_2
ENTITYNUMBER
BEGINDATE
ENDDATE
1
80
700
80
2022-01-01
2022-12-31
2
80
700
80
2022-01-01
2022-12-31
3
4
81
4
82
702
82
2022-10-01
2022-11-15
so we need to weave this current data, with the temp table, how convenient we made it a CTE already...
so the next partial step is:
WITH table_oee_valuelog(equipmentid, begintime, quantity, kpiinstanceid) as (
select * from values
(1, '2022-11-14 13:26:01'::timestamp_ntz, 10, 100),
(1, '2022-11-14 13:26:01'::timestamp_ntz, 11, 100),
(1, '2022-11-14 13:34:01'::timestamp_ntz, 12, 100),
(2, '2022-11-14 13:34:01'::timestamp_ntz, 20, 100),
(3, '2022-11-14 13:34:01'::timestamp_ntz, 30, 100),
(4, '2022-11-14 13:34:01'::timestamp_ntz, 44, 100)
), table_kpiinstance(id, kpidefinitionid) as (
select * from values
(100, 'COUNT-OUT:extra stuff')
), table_equipment(id, name, parentequipmentid, shiftcalendarentitynumber) as (
select * from values
(1,'equipment one', 2, null),
(2,'equipment two', null, 80),
(3,'equipment three', 4, 81),
(4,'equipment four', null, 82)
), table_shift(id, shiftcalendarid, reference) as (
select * from values
(1001, 9001, 'a')
), table_shiftcalendar(id, entitynumber, begindate, enddate) as (
select * from values
(699, 80, '2021-01-01'::date, '2021-12-31'::date),
(700, 80, '2022-01-01'::date, '2022-12-31'::date),
(701, 80, '2023-01-01'::date, '2023-12-31'::date),
--(701, 81, '2022-02-01'::date, '2022-11-30'::date),
(702, 82, '2022-10-01'::date, '2022-11-15'::date)
), temp_sub_select as (
SELECT
vl.equipmentid as productionunit,
timeadd('minute', truncate(minute(vl.BeginTime)/30)*30, date_trunc('hour', vl.BeginTime)) as datetime,
SUM(vl.quantity) AS scrapquantity
FROM table_oee_valuelog as vl
INNER JOIN table_kpiinstance as ki
ON ki.ID = vl.KPIInstanceID
AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY 1,2
), cte_GetEquipmentShiftCalendarID_part_a/*(id, shiftCalendarID)*/ as (
with recursive rec_cte (id, parentequipmentid, shiftcalendarentitynumber) as (
select
ID,
ParentEquipmentID,
ShiftCalendarEntityNumber
FROM table_equipment
UNION ALL
SELECT
r.ID,
p.ParentEquipmentID,
p.ShiftCalendarEntityNumber
FROM rec_cte as r
INNER JOIN table_equipment p
ON p.ID = r.ParentEquipmentID
AND r.ShiftCalendarEntityNumber IS NULL
)
select
c.id,
sc.id as shiftCalendarID,
sc.begindate, sc.enddate
from rec_cte as c
left join table_shiftcalendar as sc
on sc.entitynumber = c.ShiftCalendarEntityNumber
where shiftcalendarentitynumber is not null
)--, last_calendar_per_equipment as (
select *
,iff(c.enddate is null or c.enddate > t.datetime, 1, 2) as order_a
,row_number() over (partition by t.productionunit, t.datetime order by order_a, c.begindate desc) as rn
from temp_sub_select as t
left join cte_GetEquipmentShiftCalendarID_part_a as c
on t.productionunit = c.id
and c.begindate <= t.datetime
;)
this gives:
PRODUCTIONUNIT
DATETIME
SCRAPQUANTITY
ID
SHIFTCALENDARID
BEGINDATE
ENDDATE
ORDER_A
RN
1
2022-11-14 13:00:00.000
21
1
700
2022-01-01
2022-12-31
1
1
1
2022-11-14 13:00:00.000
21
1
699
2021-01-01
2021-12-31
2
2
1
2022-11-14 13:30:00.000
12
1
700
2022-01-01
2022-12-31
1
1
1
2022-11-14 13:30:00.000
12
1
699
2021-01-01
2021-12-31
2
2
2
2022-11-14 13:30:00.000
20
2
700
2022-01-01
2022-12-31
1
1
2
2022-11-14 13:30:00.000
20
2
699
2021-01-01
2021-12-31
2
2
3
2022-11-14 13:30:00.000
30
1
1
4
2022-11-14 13:30:00.000
44
4
702
2022-10-01
2022-11-15
1
1
last step of this function can be handled with this CTE which we can join to the prior results, and take if the prior results are null.
select
t.datetime,
sc.id
from (
select distinct datetime
from temp_sub_select
) as t
join table_shiftcalendar as sc
on sc.begindate <= t.datetime
qualify row_number() over (partition by t.datetime order by sc.begindate desc) = 1
weave those together and a little data change:
WITH table_oee_valuelog(equipmentid, begintime, quantity, kpiinstanceid) as (
select * from values
(1, '2022-11-14 13:26:01'::timestamp_ntz, 10, 100),
(1, '2022-11-14 13:26:01'::timestamp_ntz, 11, 100),
(1, '2022-11-14 13:34:01'::timestamp_ntz, 12, 100),
(2, '2022-11-14 13:34:01'::timestamp_ntz, 20, 100),
(3, '2022-11-14 13:34:01'::timestamp_ntz, 30, 100),
(4, '2022-11-14 13:34:01'::timestamp_ntz, 44, 100)
), table_kpiinstance(id, kpidefinitionid) as (
select * from values
(100, 'COUNT-OUT:extra stuff')
), table_equipment(id, name, parentequipmentid, shiftcalendarentitynumber) as (
select * from values
(1,'equipment one', 2, null),
(2,'equipment two', null, 80),
(3,'equipment three', 4, 81),
(4,'equipment four', null, 82)
), table_shift(id, shiftcalendarid, reference) as (
select * from values
(1001, 9001, 'a')
), table_shiftcalendar(id, entitynumber, begindate, enddate) as (
select * from values
(699, 80, '2021-01-01'::date, '2021-12-31'::date),
(700, 80, '2022-01-01'::date, '2022-12-31'::date),
(701, 80, '2023-01-01'::date, '2023-12-31'::date),
--(701, 81, '2022-02-01'::date, '2022-11-30'::date),
(702, 82, '2022-10-01'::date, '2022-11-15'::date),
(703, 89, '2022-11-01'::date, '2022-11-15'::date)
), temp_sub_select as (
SELECT
vl.equipmentid as productionunit,
timeadd('minute', truncate(minute(vl.BeginTime)/30)*30, date_trunc('hour', vl.BeginTime)) as datetime,
SUM(vl.quantity) AS scrapquantity
FROM table_oee_valuelog as vl
INNER JOIN table_kpiinstance as ki
ON ki.ID = vl.KPIInstanceID
AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY 1,2
), cte_GetEquipmentShiftCalendarID_part_a/*(id, shiftCalendarID)*/ as (
with recursive rec_cte (id, parentequipmentid, shiftcalendarentitynumber) as (
select
ID,
ParentEquipmentID,
ShiftCalendarEntityNumber
FROM table_equipment
UNION ALL
SELECT
r.ID,
p.ParentEquipmentID,
p.ShiftCalendarEntityNumber
FROM rec_cte as r
INNER JOIN table_equipment p
ON p.ID = r.ParentEquipmentID
AND r.ShiftCalendarEntityNumber IS NULL
)
select
c.id,
sc.id as shiftCalendarID,
sc.begindate, sc.enddate
from rec_cte as c
left join table_shiftcalendar as sc
on sc.entitynumber = c.ShiftCalendarEntityNumber
where shiftcalendarentitynumber is not null
), cte_GetEquipmentShiftCalendarID_part_b as (
select t.productionunit,
t.org_datetime,
t.datetime,
c.shiftCalendarID
from (
select
productionunit,
datetime as org_datetime,
nvl(datetime, CURRENT_DATE) as datetime /* handle the null case from the T-SQL */
from temp_sub_select
) as t
left join cte_GetEquipmentShiftCalendarID_part_a as c
on t.productionunit = c.id
and c.begindate <= t.datetime
qualify row_number() over (partition by t.productionunit, t.datetime
order by iff(c.enddate is null or c.enddate > t.datetime, 1, 2), c.begindate desc) = 1
), max_shiftCalendar_per_datetime as (
select
t.datetime,
sc.id
from (
select distinct nvl(datetime, CURRENT_DATE) as datetime
from temp_sub_select
) as t
join table_shiftcalendar as sc
on sc.begindate <= t.datetime
qualify row_number() over (partition by t.datetime order by sc.begindate desc) = 1
)--, last_calendar_per_equipment as (
select
a.productionunit
,a.org_datetime
,a.shiftCalendarID, b.id
,nvl(a.shiftCalendarID, b.id) as shiftCalendarID
from cte_GetEquipmentShiftCalendarID_part_b as a
join max_shiftCalendar_per_datetime as b
on a.datetime = b.datetime
;)
gives:
PRODUCTIONUNIT
ORG_DATETIME
SHIFTCALENDARID
ID
SHIFTCALENDARID_2
1
2022-11-14 13:00:00.000
700
703
700
1
2022-11-14 13:30:00.000
700
703
700
2
2022-11-14 13:30:00.000
700
703
700
3
2022-11-14 13:30:00.000
703
703
4
2022-11-14 13:30:00.000
702
703
702
Mostly Complete answer:
So I striped ProductionDate and the two fixed string from my answer but:
--CREATE VIEW proj.pvw_PowerBI_ActualUnits
WITH table_oee_valuelog(equipmentid, begintime, quantity, kpiinstanceid) as (
select * from values
(1, '2022-11-14 13:26:01'::timestamp_ntz, 10, 100),
(1, '2022-11-14 13:26:01'::timestamp_ntz, 11, 100),
(1, '2022-11-14 13:34:01'::timestamp_ntz, 12, 100),
(2, '2022-11-14 13:34:01'::timestamp_ntz, 20, 100),
(3, '2022-11-14 13:34:01'::timestamp_ntz, 30, 100),
(4, '2022-11-14 13:34:01'::timestamp_ntz, 44, 100)
), table_kpiinstance(id, kpidefinitionid) as (
select * from values
(100, 'COUNT-OUT:extra stuff')
), table_equipment(id, name, parentequipmentid, shiftcalendarentitynumber) as (
select * from values
(1,'equipment one', 2, null),
(2,'equipment two', null, 80),
(3,'equipment three', 4, 81),
(4,'equipment four', null, 82)
), table_shift(id, shiftcalendarid, reference, FromDay, FromTimeOfDay, TillTimeOfDay) as (
select * from values
(1001, 700, 'a', 8, '06:00'::time,'18:00'::time),
(1001, 702, 'a', 5, '06:00'::time,'18:00'::time),
(1001, 703, 'a', 4, '06:00'::time,'18:00'::time)
), table_shiftcalendar(id, entitynumber, begindate, enddate, name, PeriodInDays) as (
select * from values
(699, 80, '2021-01-01'::date, '2021-12-31'::date, 'Factory', 10),
(700, 80, '2022-01-01'::date, '2022-12-31'::date, 'Factory', 10),
(701, 80, '2023-01-01'::date, '2023-12-31'::date, 'Factory', 10),
--(701, 81, '2022-02-01'::date, '2022-11-30'::date, 'Factory', 10),
(702, 82, '2022-10-01'::date, '2022-11-15'::date, 'Factory', 10),
(703, 89, '2022-11-01'::date, '2022-11-15'::date, 'Factory', 10)
), temp_sub_select as (
SELECT
vl.equipmentid as productionunit,
timeadd('minute', truncate(minute(vl.BeginTime)/30)*30, date_trunc('hour', vl.BeginTime)) as datetime,
SUM(vl.quantity) AS scrapquantity
FROM table_oee_valuelog as vl
INNER JOIN table_kpiinstance as ki
ON ki.ID = vl.KPIInstanceID
AND ki.KPIDefinitionID LIKE 'COUNT-OUT:%'
GROUP BY 1,2
), cte_GetEquipmentShiftCalendarID_part_a as (
with recursive rec_cte (id, parentequipmentid, shiftcalendarentitynumber) as (
select
ID,
ParentEquipmentID,
ShiftCalendarEntityNumber
FROM table_equipment
UNION ALL
SELECT
r.ID,
p.ParentEquipmentID,
p.ShiftCalendarEntityNumber
FROM rec_cte as r
INNER JOIN table_equipment p
ON p.ID = r.ParentEquipmentID
AND r.ShiftCalendarEntityNumber IS NULL
)
select
c.id,
sc.id as shiftCalendarID,
sc.begindate, sc.enddate
from rec_cte as c
left join table_shiftcalendar as sc
on sc.entitynumber = c.ShiftCalendarEntityNumber
where shiftcalendarentitynumber is not null
), cte_GetEquipmentShiftCalendarID_part_b as (
select t.productionunit,
t.org_datetime,
t.datetime,
c.shiftCalendarID
from (
select
productionunit,
datetime as org_datetime,
nvl(datetime, CURRENT_DATE) as datetime /* handle the null case from the T-SQL */
from temp_sub_select
) as t
left join cte_GetEquipmentShiftCalendarID_part_a as c
on t.productionunit = c.id
and c.begindate <= t.datetime
qualify row_number() over (partition by t.productionunit, t.datetime
order by iff(c.enddate is null or c.enddate > t.datetime, 1, 2), c.begindate desc) = 1
), max_shiftCalendar_per_datetime as (
select
t.datetime,
sc.id
from (
select distinct nvl(datetime, CURRENT_DATE) as datetime
from temp_sub_select
) as t
join table_shiftcalendar as sc
on sc.begindate <= t.datetime
qualify row_number() over (partition by t.datetime order by sc.begindate desc) = 1
), last_calendar_per_equipment as (
select
a.productionunit
,a.org_datetime
,nvl(a.shiftCalendarID, b.id) as shiftCalendarID
from cte_GetEquipmentShiftCalendarID_part_b as a
join max_shiftCalendar_per_datetime as b
on a.datetime = b.datetime
), cfn_GetShiftIDFromDateTime as (
with t0 as (
select
x.productionunit
,x.org_datetime
,x.org_datetime::time as org_time
,x.ShiftCalendarID
,DATEDIFF( day, BeginDate, x.org_datetime ) % PeriodInDays + 1 AS CurDay
,( CurDay + PeriodInDays - 2 ) % PeriodInDays + 1 AS PrvDay
from last_calendar_per_equipment as x
join table_shiftcalendar as sc
where sc.id = x.shiftCalendarID
OR ( x.shiftCalendarID IS NULL
AND sc.Name = 'Factory'
AND sc.BeginDate <= x.org_datetime )
QUALIFY row_number() over (partition by x.productionunit, x.org_datetime order by sc.begindate desc) = 1
)
SELECT
s.id
,s.reference
,productionunit
,org_datetime
,s.ShiftCalendarID
,s.FromDay, s.FromTimeOfDay, s.TillTimeOfDay, T0.CurDay, t0.org_time
FROM table_shift as s, T0
WHERE s.ShiftCalendarID = T0.ShiftCalendarID
AND ( ( s.FromDay = T0.CurDay AND s.FromTimeOfDay <= t0.org_time AND s.TillTimeOfDay > t0.org_time )
OR ( s.FromDay = T0.CurDay AND s.FromTimeOfDay >= s.TillTimeOfDay AND s.FromTimeOfDay <= t0.org_time )
OR ( s.FromDay = T0.PrvDay AND s.FromTimeOfDay >= s.TillTimeOfDay AND s.TillTimeOfDay > t0.org_time )
)
)
SELECT
e.name AS productionunit,
temp.datetime AS datetime,
s.reference AS shift,
temp.DateTime::time AS Time,
temp.ScrapQuantity AS ScrapQuantity,
s.ID
FROM temp_sub_select as temp
INNER JOIN table_equipment e
ON e.ID = temp.ProductionUnit
INNER JOIN cfn_GetShiftIDFromDateTime s
ON s.productionunit = temp.ProductionUnit
and temp.datetime = s.org_datetime
as far as I can follow, does what your functions do, and unrolls the correlated query, as that would never work in Snowflake.
PRODUCTIONUNIT
DATETIME
SHIFT
TIME
SCRAPQUANTITY
ID
equipment one
2022-11-14 13:00:00.000
a
13:00:00
21
1001
equipment one
2022-11-14 13:30:00.000
a
13:30:00
12
1001
equipment two
2022-11-14 13:30:00.000
a
13:30:00
20
1001
equipment three
2022-11-14 13:30:00.000
a
13:30:00
30
1001
equipment four
2022-11-14 13:30:00.000
a
13:30:00
44
1001
Not so bad for five hours work...

I want to query the no of transaction done by a customer in a particular year, but the output should come year wise for each customer in table format

Output should be in below format, but I am getting wrong output:
Where 2019,2020,2021 column contains transaction done by customer in respectively 2019, 2020, 2021. Also if transactions in 2019,2020,2021 is equal Max_transaction is populated with first non-zero transaction year .
customer_name 2019 2020 2021 Max_transaction_year total_transaction
pug 2 1 0 2019 4
hari 0 1 1 2020 2
adh 0 0 1 2021 1
Sample table and data :
Also note that the first two digits in "tid" represent the year of transaction. Eg: 19597 -'19' represents 2019 and so on for 2020 and 2021.
create table client (cid int,cname char(10));
create table trans (tid int,cid int);
insert into client values(102,'pug'),(107,'ravi'),(109,'hari'),(105,'pon'),(106,'adh'),(104,'bav'),(101,'kat');
insert into trans values(19597,102),(19567,102),(20325,109),(21789,106),(17432,106),(21786,109),(20302,102),(17301,103);
Thanks in advance
Schema (MySQL v8.0)
create table client (cid int,cname char(10));
create table trans (tid int,cid int);
insert into client values(102,'pug'),(107,'ravi'),(109,'hari'),(105,'pon'),(106,'adh'),(104,'bav'),(101,'kat');
insert into trans values(19597,102),(19567,102),(20325,109),(21789,106),(17432,106),(21786,109),(20302,102),(17301,103);
Query #1
SELECT
customer_name,
SUM(
CASE WHEN year=2019 THEN no_transactions ELSE 0 END
) as '2019',
SUM(
CASE WHEN year=2020 THEN no_transactions ELSE 0 END
) as '2020',
SUM(
CASE WHEN year=2021 THEN no_transactions ELSE 0 END
) as '2021',
MAX(
CASE WHEN rn=1 THEN year ELSE 0 END
) as Max_transaction_year,
SUM(no_transactions) as total_transaction
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY customer_name ORDER BY no_transactions DESC) rn
FROM (
SELECT
c.cname as customer_name,
2000+FLOOR(tid / 1000) as year ,
COUNT(1) as no_transactions
FROM
trans t
INNER JOIN
client c ON t.cid = c.cid
WHERE
FLOOR(tid / 1000) BETWEEN 19 and 21
GROUP BY
c.cname, 2000+FLOOR(tid / 1000)
) p1
) p2
GROUP BY customer_name;
customer_name
2019
2020
2021
Max_transaction_year
total_transaction
adh
0
0
1
2021
1
hari
0
1
1
2020
2
pug
2
1
0
2019
3
View on DB Fiddle
I think a somewhat simpler method just uses conditional aggregation:
select cname, cnt_2019, cnt_2020, cnt_2021,
(case greatest(cnt_2019, cnt_2020, cnt_2021)
when cnt_2019 then '2019'
when cnt_2020 then '2020'
when cnt_2021 then '2021'
end) as max_year,
total_transactions
from (select c.cname, c.cid,
sum(year = '2019') as cnt_2019,
sum(year = '2020') as cnt_2020,
sum(year = '2021') as cnt_2021,
count(*) as total_transactions
from client c join
(select t.*, concat('20', left(t.tid, 2)) as year
from trans t
) t
on c.cid = t.cid
where year >= '2019' and year <= '2021'
group by c.cname, c.cid
) ct
order by cname, cid;
Here is a db<>fiddle.

sql server 2008 running totals between 2 dates

I need to get running totals between 2 dates in my sql server table and update the records simultaneoulsy. My data is as below and ordered by date,voucher_no
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
-------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
13/10/2017 3 105 20 125
Now if i insert a record with voucher_no 4 on 12/10/2017 the output should be like
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
12/10/2017 4 105 4 109
13/10/2017 3 109 20 129
I have seen several examples which find running totals upto a certain date but not between 2 dates or from a particular date to end of file
You should consider changing your database structure. I think it will be better to keep DATE, VOUCHER_NO, DEBITS, CREDITS in one table. And create view to calculate balances. In that case you will not have to update table after each insert. In this case your table will look like
create table myTable (
DATE date
, VOUCHER_NO int
, DEBITS int
, CREDITS int
)
insert into myTable values
('20171010', 1, 10, null),( '20171012', 2, null, 5)
, ('20171013', 3, 20, null), ('20171012', 4, 4, null)
And view will be
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
select
a.DATE, a.VOUCHER_NO, a.DEBITS, a.CREDITS
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal, a.DEBITS, a.CREDITS
Here's another solution if you can not change your db structure. In this case you must run update statement each time after inserts. In both cases I assume that initial balance is 100 while recalculation
create table myTable (
DATE date
, VOUCHER_NO int
, OPEN_BAL int
, DEBITS int
, CREDITS int
, CLOS_BAL int
)
insert into myTable values
('20171010', 1, 100, 10, null, 110)
,( '20171012', 2, 110, null, 5, 105)
, ('20171013', 3, 105, 20, null, 125)
, ('20171012', 4, null, 4, null, null)
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
, cte2 as (
select
a.DATE, a.VOUCHER_NO
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal
)
update a
set a.OPEN_BAL = b.OPEN_BAL, a.CLOS_BAL = b.CLOS_BAL
from
myTable a
join cte2 b on a.DATE = b.DATE and a.VOUCHER_NO = b.VOUCHER_NO

Getting max value in a specific peroid of time in MySQL

I have a table like this(tblFuel):
time fuel
2014-11-04 17:11:08 231
2014-11-04 17:34:16 254
2014-11-04 18:03:48 241
2014-11-04 18:41:34 137
2014-11-04 18:43:42 111
Now I expect to show the biggest value of fuel during each 1 hour. For example: max from 17:00:00 to 17:59:59 and so on. And follow the previous requirement, the expected result should:
time fuel
2014-11-04 17:34:16 254
2014-11-04 18:03:48 241
So what should I do to achieve this result?
create table tblFuel (time timestamp, fuel int);
insert into tblFuel values ('2014-11-04 17:11:08', 231);
insert into tblFuel values ('2014-11-04 17:34:16', 254);
insert into tblFuel values ('2014-11-04 18:03:48', 241);
insert into tblFuel values ('2014-11-04 18:41:34', 137);
insert into tblFuel values ('2014-11-04 18:43:42', 111);
select
*
from tblFuel
where concat(date(time), hour(time), fuel) in
(select
concat(date(time), hour(time), max(fuel))
from tblFuel
group by
date(time),
hour(time))
Returns:
time fuel
2014-11-04 17:34:16 254
2014-11-04 18:03:48 241
This query will be helpful.
DECLARE #tblFuel TABLE
(
Val INTEGER,
Time DATETIME
)
INSERT INTO #tblFuel
SELECT '231', '2014-11-04 17:11:08' union All
SELECT '254', '2014-11-04 17:34:16' union All
SELECT '241', '2014-11-04 18:03:48' union All
SELECT '137', '2014-11-04 18:41:34' union All
SELECT '111', '2014-11-04 18:43:42'
SELECT A.Val, A.Time FROM #tblFuel AS A
Inner join
(SELECT MAX(Val) AS VAL,
CONVERT(VARCHAR(20), Time, 110) +' ' + CAST(DATEPART(hour, Time) as varchar(2)) AS Time
FROM #tblFuel GROUP BY CONVERT(VARCHAR(20), Time, 110) +' ' + CAST(DATEPART(hour, Time) as varchar(2))) AS B
ON A.Val = B.val AND CONVERT(VARCHAR(20), A.Time, 110) +' ' + CAST(DATEPART(hour, A.Time) as varchar(2)) = B.Time
Here's one way to do it. It uses the DATE_FORMAT function to group by date and hour.
SELECT ft.time, ft.fuel
FROM fuel_table ft
JOIN
(SELECT DATE_FORMAT(time, '%Y%m%d %H') date_and_hour, MAX(fuel) max_fuel
FROM fuel_table
GROUP BY date_and_hour) AS max_fuel
ON DATE_FORMAT(ft.time, '%Y%m%d %H') = max_fuel.date_and_hour
AND ft.fuel = max_fuel

Group by, with rank and sum - not getting correct output

I'm trying to sum a column with rank function and group by month, my code is
select dbo.UpCase( REPLACE( p.Agent_name,'.',' '))as Agent_name, SUM(convert ( float ,
p.Amount))as amount,
RANK() over( order by SUM(convert ( float ,Amount )) desc ) as arank
from dbo.T_Client_Pc_Reg p
group by p.Agent_name ,p.Sale_status ,MONTH(Reg_date)
having [p].Sale_status='Activated'
Currently I'm getting all total value of that column not month wise
Name amount rank
a 100 1
b 80 2
c 50 3
for a amount 100 is total amount till now but , i want get current month total amount not last months..
Maybe you just need to add a WHERE clause? Here is a minor re-write that I think works generally better. Some setup in tempdb:
USE tempdb;
GO
CREATE TABLE dbo.T_Client_Pc_Reg
(
Agent_name VARCHAR(32),
Amount INT,
Sale_Status VARCHAR(32),
Reg_date DATETIME
);
INSERT dbo.T_Client_Pc_Reg
SELECT 'a', 50, 'Activated', GETDATE()
UNION ALL SELECT 'a', 50, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'NotActivated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()-40;
Then the query:
SELECT
Agent_name = UPPER(REPLACE(Agent_name, '.', '')),
Amount = SUM(CONVERT(FLOAT, Amount)),
arank = RANK() OVER (ORDER BY SUM(CONVERT(FLOAT, Amount)) DESC)
FROM dbo.T_Client_Pc_Reg
WHERE Reg_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
AND Reg_date < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) + 1, 0)
AND Sale_status = 'Activated'
GROUP BY UPPER(REPLACE(Agent_name, '.', ''))
ORDER BY arank;
Now cleanup:
USE tempdb;
GO
DROP TABLE dbo.T_Client_Pc_Reg;