Я новичок в BigQuery, но мне удалось получить следующий скрипт для правильного расчета пасхального воскресенья за определенный год, используя логику, которую я получил от Картера https://www.rmg.co.uk/stories/topics/when -easter#:~:text=%20simple%20standard%20definition%20of,Пасха%20is%20the%20next%20воскресенье.
DECLARE year INT64;
DECLARE D INT64;
DECLARE E INT64;
DECLARE Q INT64;
DECLARE easter_date STRING;
-- Set year
SET year = 1998; -- Replace with the desired year
-- Step 1: Calculate D = '225' - 11 * (year MOD 19)
SET D = 225 - 11 * MOD(CAST(year AS INT64), 19);
-- Step 2: If D is greater than 50 then subtract multiples of 30 until the resulting new value of D is less than 51
WHILE D > 50 DO
SET D = D - 30;
END WHILE;
-- Step 3: If D is greater than 48 subtract 1 from it
IF D > 48 THEN
SET D = D - 1;
END IF;
-- Step 4: Calculate E = (year + CAST(FLOOR(year / 4) AS INT64) + D + 1) MOD 7
SET E = MOD(year + CAST(FLOOR(year / 4) AS INT64) + D + 1, 7);
-- Step 5: Calculate Q = D + 7 - E
SET Q = D + 7 - E;
-- Step 6: Determine the date of Easter Sunday
IF Q < 32 THEN
SET easter_date = CONCAT(CAST(year AS STRING), '-03-', CAST(Q AS STRING) );
ELSE
SET easter_date = CONCAT(CAST(year AS STRING), '-04-', CAST(Q - 31 AS STRING) );
END IF;
-- Output the result
SELECT CAST(easter_date AS DATE) AS easter_sunday;
Как уже упоминалось, сценарий работает отлично, однако я сейчас создаю сценарий праздников, и мне нужно включить в него этот расчет. Я пытаюсь избежать создания функции, но включить эту логику в какой-то CTE оказывается сложно - я предполагаю, что это из-за циклов, которые мне нужно было написать? По сути, я хочу получить Пасхальное воскресенье для ряда лет (1990–2099), которые я могу добавить в свою текущую таблицу дат.
Любая помощь/совет, пожалуйста?
Вместо использования процедурного языка вы можете использовать линейные вычисления для расчета более 1 года в одном запросе:
WITH
t1 as
(
select year, 225 - 11 * MOD(year, 19) as d, -- 203
from unnest(generate_array(1900, 2100)) as year
),
t2 as
(
select
year,
mod(d - 21, 30) + 21 as d
from t1
),
t3 as
(
select
year,
if (d > 48, d-1, d) as d
from t2
),
t4 as
(
select
year, d,
D + 7 -
MOD(year + CAST(FLOOR(year / 4) AS INT64) + D + 1, 7) -- this line calculates e
as q
from t3
),
easter_list as
(
SELECT
year, d,
date(date("2000-03-01") + interval (q-1) day + interval (year - 2000) year) as x
from t4
)
select *
from easter_list
Спасибо, все работает быстро и точно. Я опубликую свою последнюю попытку, которая работает, но не так быстро.
Моя попытка
WITH RECURSIVE year_range AS (
SELECT 1998 AS year -- Replace with the starting year
UNION ALL
SELECT year + 1
FROM year_range
WHERE year < 2030 -- Replace with the ending year
),
easter_calculations AS (
SELECT
year,
225 - 11 * MOD(year, 19) AS D
FROM year_range
),
adjusted_D AS (
SELECT
year,
D
FROM easter_calculations
UNION ALL
SELECT
year,
D - 30
FROM adjusted_D
WHERE D > 50
),
final_D AS (
SELECT
year,
CASE
WHEN D > 48 THEN D - 1
ELSE D
END AS D
FROM (
SELECT year, D, ROW_NUMBER() OVER (PARTITION BY year ORDER BY D) AS rn
FROM adjusted_D
WHERE D < 51
)
WHERE rn = 1
),
easter_sunday AS (
SELECT
year,
D AS final_D,
MOD(year + CAST(FLOOR(year / 4) AS INT64) + D + 1, 7) AS E
FROM final_D
),
easter_date_calc AS (
SELECT
year,
final_D,
final_D + 7 - E AS Q
FROM easter_sunday
),
easter_dates AS (
SELECT
year,
CASE
WHEN Q < 32 THEN CONCAT(year, '-03-', LPAD(CAST(Q AS STRING), 2, '0'))
ELSE CONCAT(year, '-04-', LPAD(CAST(Q - 31 AS STRING), 2, '0'))
END AS easter_date
FROM easter_date_calc
)
SELECT
year,
CAST(easter_date AS DATE) AS easter_sunday
FROM easter_dates
ORDER BY year;
Что, если вы создадите статическую таблицу, содержащую все даты пасхального воскресенья, а затем просто запросите ее по годам? Вот таблица таких данных, которую можно использовать для загрузки в BQ... census.gov/data/software/x13as/genhol/easter-dates.html Почему вы избегаете функции?