I guess there is no simple, short query which produces the expected result.
You have to implement a heavy mix of steps (or you need to do it in another way rather than in pure SQL):
Spotting real gaps
You need to know when one month jumps straight to the next and when it doesn’t. SQL won’t just “see” that for you. You have to compare each date to the one before and say “yes, that’s a gap” or “no, that’s consecutive.”
Bunching back‑to‑back months together
Once you know where the gaps are, you still have to turn each run of consecutive months into a single row. That means to tag every row with a bucket number, then collapse those buckets with a simple MIN/MAX call.
Handling as many IDs as you’ve got
You can’t assume there are just one or two IDs. The same logic has to work if you have dozens or hundreds, each with its own pattern of gaps and runs.
Ending the last run differently
Every ID’s final enabled period is not supposed to end where it really ends. It rather needs the date 3000‑01‑01 to show the period is “ongoing.” You have to detect “this is the last group for that ID” and swap in the fake end date.
Putting it all together
To keep it in a single query in pure SQL, you need to...
First tag each row with “where’s the previous date?”
Then turn those tags into running group numbers
Then group by those numbers to get from/to
Then find the final group and patch its end date
Each of those steps is straightforward on its own, but to combine them inside one SQL query is quite hard. The following query is the best solution I could build using ANSI-compliant functions:
SELECT
id,
MIN(as_at_date) AS from_date,
/* If this group's end date is the last date we see for this ID,
make it open‑ended as 3000‑01‑01 */
CASE
WHEN MAX(as_at_date) = MAX(MAX(as_at_date)) OVER (PARTITION BY id)
THEN CAST('3000-01-01' AS DATE)
ELSE MAX(as_at_date)
END AS to_date,
'Y' AS Enabled_Flag
FROM (
SELECT
id,
as_at_date,
/*
Build groups so that true month‑to‑month runs get the same group:
1) turn the date into a month number (year * 12 + month)
2) subtract the row’s sequence number for that ID
as long as dates are back‑to‑back months,
the difference stays the same. When there's a gap, it changes.
*/
(EXTRACT(YEAR FROM as_at_date) * 12
+ EXTRACT(MONTH FROM as_at_date))
- ROW_NUMBER() OVER (PARTITION BY id ORDER BY as_at_date)
AS grp
FROM your_table
WHERE Enabled_Flag = 'Y'
) t
-- group by id and group to collapse each run into one row
GROUP BY id, grp
ORDER BY id, from_date;
This produces the expected result for your sample data, I verified this on this db<>fiddle (the fiddle is a Postgres DB because I could not find one for Teradata, but the query should do in Teradata, too).
Note 1: There are maybe options to simplify this code (for example, in Postgres you likely could use some functions like RANGE_MERGE). But this requires RDBMS-specific functions. Since I don't know much about Teradata, I stuck to "Standard SQL".
Note 2: What about rows with other values in the column Enabled_Flag?
enabled='N'do they exist and if so how should they be treated?as_at_dateto a period covering the full month usingperiod(as_at_date, oAdd_month(as_at_date)