CREATE TABLE access_log (
    "url" STRING,
    user_id BIGINT,
    ts TIMESTAMP TIME INDEX,
    PRIMARY KEY ("url", user_id)
);

Affected Rows: 0

CREATE TABLE access_log_10s (
    "url" STRING,
    time_window timestamp time INDEX,
    state BINARY,
    PRIMARY KEY ("url")
);

Affected Rows: 0

CREATE FLOW calc_access_log_10s SINK TO access_log_10s
AS
SELECT
    "url",
    date_bin('10s'::INTERVAL, ts) AS time_window,
    hll(user_id) AS state
FROM
    access_log
GROUP BY
    "url",
    time_window;

Affected Rows: 0

-- insert 4 rows of data
INSERT INTO access_log VALUES
        ("/dashboard", 1, "2025-03-04 00:00:00"),
        ("/dashboard", 1, "2025-03-04 00:00:01"),
        ("/dashboard", 2, "2025-03-04 00:00:05"),
        ("/not_found", 3, "2025-03-04 00:00:11"),
        ("/dashboard", 4, "2025-03-04 00:00:15");

Affected Rows: 5

-- SQLNESS REPLACE (ADMIN\sFLUSH_FLOW\('\w+'\)\s+\|\n\+-+\+\n\|\s+)[0-9]+\s+\| $1 FLOW_FLUSHED  |
ADMIN FLUSH_FLOW('calc_access_log_10s');

+-----------------------------------------+
| ADMIN FLUSH_FLOW('calc_access_log_10s') |
+-----------------------------------------+
|  FLOW_FLUSHED  |
+-----------------------------------------+

-- query should return 3 rows
-- SQLNESS SORT_RESULT 3 1
SELECT "url", time_window FROM access_log_10s
ORDER BY
    time_window;

+------------+---------------------+
| url        | time_window         |
+------------+---------------------+
| /dashboard | 2025-03-04T00:00:00 |
| /dashboard | 2025-03-04T00:00:10 |
| /not_found | 2025-03-04T00:00:10 |
+------------+---------------------+

-- use hll_count to query the approximate data in access_log_10s
-- SQLNESS SORT_RESULT 3 1
SELECT "url", time_window, hll_count(state) FROM access_log_10s
ORDER BY
    time_window;

+------------+---------------------+---------------------------------+
| url        | time_window         | hll_count(access_log_10s.state) |
+------------+---------------------+---------------------------------+
| /dashboard | 2025-03-04T00:00:00 | 2                               |
| /dashboard | 2025-03-04T00:00:10 | 1                               |
| /not_found | 2025-03-04T00:00:10 | 1                               |
+------------+---------------------+---------------------------------+

-- further, we can aggregate 10 seconds of data to every minute, by using hll_merge to merge 10 seconds of hyperloglog state
-- SQLNESS SORT_RESULT 3 1
SELECT
    "url",
    date_bin('1 minute'::INTERVAL, time_window) AS time_window_1m,
    hll_count(hll_merge(state)) as uv_per_min
FROM
    access_log_10s
GROUP BY
    "url",
    time_window_1m
ORDER BY
    time_window_1m;

+------------+---------------------+------------+
| url        | time_window_1m      | uv_per_min |
+------------+---------------------+------------+
| /dashboard | 2025-03-04T00:00:00 | 3          |
| /not_found | 2025-03-04T00:00:00 | 1          |
+------------+---------------------+------------+

DROP FLOW calc_access_log_10s;

Affected Rows: 0

DROP TABLE access_log_10s;

Affected Rows: 0

DROP TABLE access_log;

Affected Rows: 0

CREATE TABLE percentile_base (
    "id" INT PRIMARY KEY,
    "value" DOUBLE,
    ts timestamp(0) time index
);

Affected Rows: 0

CREATE TABLE percentile_5s (
    "percentile_state" BINARY,
    time_window timestamp(0) time index
);

Affected Rows: 0

CREATE FLOW calc_percentile_5s SINK TO percentile_5s
AS
SELECT
    uddsketch_state(128, 0.01, "value") AS "value",
    date_bin('5 seconds'::INTERVAL, ts) AS time_window
FROM
    percentile_base
WHERE
    "value" > 0 AND "value" < 70
GROUP BY
    time_window;

Affected Rows: 0

INSERT INTO percentile_base ("id", "value", ts) VALUES
    (1, 10.0, 1),
    (2, 20.0, 2),
    (3, 30.0, 3),
    (4, 40.0, 4),
    (5, 50.0, 5),
    (6, 60.0, 6),
    (7, 70.0, 7),
    (8, 80.0, 8),
    (9, 90.0, 9),
    (10, 100.0, 10);

Affected Rows: 10

-- SQLNESS REPLACE (ADMIN\sFLUSH_FLOW\('\w+'\)\s+\|\n\+-+\+\n\|\s+)[0-9]+\s+\| $1 FLOW_FLUSHED  |
ADMIN FLUSH_FLOW('calc_percentile_5s');

+----------------------------------------+
| ADMIN FLUSH_FLOW('calc_percentile_5s') |
+----------------------------------------+
|  FLOW_FLUSHED  |
+----------------------------------------+

SELECT
    time_window,
    uddsketch_calc(0.99, `percentile_state`) AS p99
FROM
    percentile_5s
ORDER BY
    time_window;

+---------------------+--------------------+
| time_window         | p99                |
+---------------------+--------------------+
| 1970-01-01T00:00:00 | 40.04777053326359  |
| 1970-01-01T00:00:05 | 59.745049810145126 |
+---------------------+--------------------+

DROP FLOW calc_percentile_5s;

Affected Rows: 0

DROP TABLE percentile_5s;

Affected Rows: 0

DROP TABLE percentile_base;

Affected Rows: 0

CREATE TABLE percentile_base (
    "id" INT PRIMARY KEY,
    "value" DOUBLE,
    ts timestamp(0) time index
);

Affected Rows: 0

CREATE TABLE percentile_5s (
    "percentile_state" BINARY,
    time_window timestamp(0) time index
);

Affected Rows: 0

CREATE TABLE percentile_10s (
    "percentile_state" BINARY,
    time_window timestamp(0) time index
);

Affected Rows: 0

CREATE FLOW calc_percentile_5s SINK TO percentile_5s
AS
SELECT
    uddsketch_state(128, 0.01, CASE WHEN "value" > 0 AND "value" < 70 THEN "value" ELSE NULL END) AS "value",
    date_bin('5 seconds'::INTERVAL, ts) AS time_window
FROM
    percentile_base
GROUP BY
    time_window;

Affected Rows: 0

CREATE FLOW calc_percentile_10s SINK TO percentile_10s
AS
SELECT
    uddsketch_merge(128, 0.01, percentile_state),
    date_bin('10 seconds'::INTERVAL, time_window) AS time_window
FROM
    percentile_5s
GROUP BY
    date_bin('10 seconds'::INTERVAL, time_window);

Affected Rows: 0

INSERT INTO percentile_base ("id", "value", ts) VALUES
    (1, 10.0, 1),
    (2, 20.0, 2),
    (3, 30.0, 3),
    (4, 40.0, 4),
    (5, 50.0, 5),
    (6, 60.0, 6),
    (7, 70.0, 7),
    (8, 80.0, 8),
    (9, 90.0, 9),
    (10, 100.0, 10);

Affected Rows: 10

-- SQLNESS REPLACE (ADMIN\sFLUSH_FLOW\('\w+'\)\s+\|\n\+-+\+\n\|\s+)[0-9]+\s+\| $1 FLOW_FLUSHED  |
ADMIN FLUSH_FLOW('calc_percentile_5s');

+----------------------------------------+
| ADMIN FLUSH_FLOW('calc_percentile_5s') |
+----------------------------------------+
|  FLOW_FLUSHED  |
+----------------------------------------+

-- SQLNESS REPLACE (ADMIN\sFLUSH_FLOW\('\w+'\)\s+\|\n\+-+\+\n\|\s+)[0-9]+\s+\| $1 FLOW_FLUSHED  |
ADMIN FLUSH_FLOW('calc_percentile_10s');

+-----------------------------------------+
| ADMIN FLUSH_FLOW('calc_percentile_10s') |
+-----------------------------------------+
|  FLOW_FLUSHED  |
+-----------------------------------------+

SELECT
    time_window,
    uddsketch_calc(0.99, percentile_state) AS p99
FROM
    percentile_5s
ORDER BY
    time_window;

+---------------------+--------------------+
| time_window         | p99                |
+---------------------+--------------------+
| 1970-01-01T00:00:00 | 40.04777053326359  |
| 1970-01-01T00:00:05 | 59.745049810145126 |
| 1970-01-01T00:00:10 |                    |
+---------------------+--------------------+

SELECT
    time_window,
    uddsketch_calc(0.99, percentile_state) AS p99
FROM
    percentile_10s
ORDER BY
    time_window;

+---------------------+--------------------+
| time_window         | p99                |
+---------------------+--------------------+
| 1970-01-01T00:00:00 | 59.745049810145126 |
| 1970-01-01T00:00:10 |                    |
+---------------------+--------------------+

DROP FLOW calc_percentile_5s;

Affected Rows: 0

DROP FLOW calc_percentile_10s;

Affected Rows: 0

DROP TABLE percentile_5s;

Affected Rows: 0

DROP TABLE percentile_10s;

Affected Rows: 0

DROP TABLE percentile_base;

Affected Rows: 0

