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...