Определить пасхальное воскресенье BigQuery

Я новичок в 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), которые я могу добавить в свою текущую таблицу дат.

Любая помощь/совет, пожалуйста?

Что, если вы создадите статическую таблицу, содержащую все даты пасхального воскресенья, а затем просто запросите ее по годам? Вот таблица таких данных, которую можно использовать для загрузки в BQ... census.gov/data/software/x13as/genhol/easter-dates.html Почему вы избегаете функции?

Kolban 21.06.2024 14:47
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
1
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вместо использования процедурного языка вы можете использовать линейные вычисления для расчета более 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

Спасибо, все работает быстро и точно. Я опубликую свою последнюю попытку, которая работает, но не так быстро.

Gray Meiring 22.06.2024 15:43

Моя попытка

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;

Другие вопросы по теме