I'm trying to create a way of inserting aggregated data into a table by using a loop with a moving cursor. I want to count records in a 1h timeframe and compare it to the average number in corresponding timeframes from the last 7 days. I would set a start of a timeframe as a variable and move it 15 minutes with each loop.
Here is what I've tried so far:
I created the table:
CREATE OR REPLACE TABLE WHILE_LOOP_count_TEST__RESULTS (
ID int NULL,
START_TIME TIMESTAMP_NTZ NULL,
END_TIME TIMESTAMP_NTZ NULL,
ID_COUNT int NULL,
PREV_7D_AVG int NULL,
DT DATETIME NULL,
"CREATE_DT" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP(),
"CREATE_USER" VARCHAR2(50) NOT NULL DEFAULT CURRENT_USER()
);
-- START VALUE
INSERT INTO WHILE_LOOP_count_TEST__RESULTS (ID, ID_Count, DT) VALUES (1, 1, '2025-02-15 12:00');
Then, I tried the following query:
EXECUTE IMMEDIATE $$
DECLARE
counter INTEGER := 1;
start_time TIMESTAMP_NTZ := '2025-02-19 14:30:20.706000000Z'::TIMESTAMP_NTZ;
end_time TIMESTAMP_NTZ := DATEADD(hour, 1, start_time);
BEGIN
WHILE (counter < 5) DO
-- INSERT
INSERT INTO WHILE_LOOP_count_TEST__RESULTS (ID, ID_COUNT, DT, PREV_7D_AVG)
SELECT ID, ID_COUNT, DT, PREV_7D_AVG
FROM (
((SELECT MAX(ID) + 1 AS ID FROM WHILE_LOOP_count_TEST__RESULTS),
COUNT(DB1.TRANS_ID) AS ID_COUNT,
DATEADD(minute, +15, (SELECT MAX(DT)
FROM WHILE_LOOP_count_TEST__RESULTS)) AS DT,
Merchant
FROM
DB1
LEFT JOIN DB2 ON DB2.EXTERNAL_IDENTIFIER = DB1.TRANS_ID
LEFT JOIN DB3 ON DB2.COUNTRY_CODE = DB3.COUNTRY_CODE
WHERE
DB2.TS > :start_time
AND DB2.TS < :end_time
AND DB2.TYPE = 'INI'
GROUP BY
merchant ,
DB3.COUNTRY_REGION) as t1
LEFT JOIN
(SELECT avg(number) as PREV_7D_AVG, merchant1 from (
(
(
select
count(TRANS_ID) as number,
COUNTRY_REGION as CONTINENT,
merchant1
from
DB1
left join DB2 on external_identifier = trans_id
left join DB3 on DB2.COUNTRY_CODE = DB3.COUNTRY_CODE
where
ts > dateadd(hour, -2, :start_time)
and ts < dateadd(hour, -1, :start_time)
group by
CONTINENT,
merchant1
having
number > 30
)
union all
(
select
count(TRANS_ID) as number,
COUNTRY_REGION as CONTINENT,
merchant1
from
DB1
left join DB2 on external_identifier = trans_id
left join DB3 on DB2.COUNTRY_CODE = DB3.COUNTRY_CODE
where
ts > dateadd(hour, -26, :start_time)
and ts < dateadd(hour, -25, :start_time)
group by
CONTINENT,
merchant1
having
number > 30
))
-- then six more unions, every one one day earlier
group by
merchant1::varchar,
CONTINENT
) as t2 ON t1.Merchant = t2.merchant1);
-- Update the start time for the next iteration
start_time := DATEADD(minute, 15, start_time);
end_time := DATEADD(hour, 1, start_time);
counter := counter + 1;
END WHILE;
RETURN counter;
END;
$$;
I feel like I'm close to fixing this problem, but I'm getting either I'm getting either "syntax error line 7 at position 17 unexpected '<'. " or "ncaught exception of type 'STATEMENT_ERROR' on line 9 at position 4 : Single-row subquery returns more than one row.", the second one if I'm not joining the t2 table but just put the subquery in the main select statement. Any suggestions?
()will change how an SQL statement runs is when they are used in arithmetic expressions. There is no order of operations in the query part of SQL -- all of the in your code can be removed -- they have no effect.