我有一个如下所示的数据集:
ITEM CITY START_Y START_W FIRST_USE_Y FIRST_USE_W VALUE
A NEW YORK 2023 30 2023 32 15000
A LONDON 2024 2 2024 2 12000
A LONDON 2024 2 2024 5 50000
B NEW YORK 2023 49 2024 1 19540
B MADRID 2023 10 2023 11 15444
首先需要对ITEM和CITY的组合进行分组。然后,对于每个组,我想每周重新采样最多 5 个数据点,并用零填充“VALUE”列,其中 FIRST_USE_Y 和 FIRST_USE_W 列的组合没有值。 START_W 和 FIRST_USE_W 是一年中的第几周(值可以从 1 到 52)。
我尝试使用 pandas 和 for 循环;有效。但因为它是一个非常大的数据集,有数百万行,而且我必须使用 SQL(我是一个新手)。这是我尝试过的代码:
WITH RECURSIVE weekly_intervals AS (
SELECT MIN(start_w) AS start_w, MAX(start_w) AS end_w
FROM citywise_values
UNION ALL
SELECT start_w + INTERVAL 1 WEEK, end_w
FROM weekly_intervals
WHERE start_w + INTERVAL 1 WEEK <= end_w
),
filled_values AS (
SELECT
w.item,
w.city,
w.start_y,
w.start_w,
COALESCE(cv.value, 0) AS value
FROM
(SELECT
item,
city,
start_y,
start_w
FROM
citywise_values
GROUP BY
item, city) w
LEFT JOIN
citywise_values cv ON w.item = cv.item
AND w.city = cv.city
AND w.start_y = cv.start_y
AND w.start_w = cv.start_w
)
SELECT
item,
city,
start_y,
start_w,
COALESCE(value, LAG(value) OVER (PARTITION BY item, city, start_y ORDER BY start_w)) AS value
FROM
filled_values
RIGHT JOIN
weekly_intervals
ON
filled_values.start_w = weekly_intervals.start_w
ORDER BY
item, city, start_y, start_w
然后我尝试使用交叉连接,并且只能为 ITEM 和 CITY 的一个组合生成结果。但我找不到如何处理整个数据集。
我不确定我能否解释清楚。因此,我发布了我手动创建的所需输出。
ITEM CITY START_Y START_W FIRST_USE_Y FIRST_USE_W VALUE
A NEW YORK 2023 30 2023 31 0
A NEW YORK 2023 30 2023 32 15000
A NEW YORK 2023 30 2023 33 0
A NEW YORK 2023 30 2023 34 0
A NEW YORK 2023 30 2023 35 0
A LONDON 2024 2 2024 2 12000
A LONDON 2024 2 2024 3 0
A LONDON 2024 2 2024 4 0
A LONDON 2024 2 2024 5 50000
A LONDON 2024 2 2024 6 0
B NEW YORK 2023 49 2023 49 0
B NEW YORK 2023 49 2023 50 0
B NEW YORK 2023 49 2023 51 0
B NEW YORK 2023 49 2023 52 0
B NEW YORK 2023 49 2024 1 19540
B MADRID 2023 10 2023 10 0
B MADRID 2023 10 2023 11 15444
B MADRID 2023 10 2023 12 0
B MADRID 2023 10 2023 13 0
B MADRID 2023 10 2023 14 0
任何帮助将不胜感激。
这里有三项使这个查询变得棘手:
投影到 5 行(我使用了表值构造函数,但还有其他选项,包括 SQL Server 2022 中的
generate_series()
或递归 CTE)
年末时的处理。这里的技巧是日期是混乱。 永远不要尝试自己做这种工作。 始终依靠平台内置的日期选项。这意味着将年/周值转换为实际日期......这就是我建议首先以这种方式存储内容的原因之一。您可以将这些值存储为日期,其中实际日期是该周的星期日值。
我确实必须对手动日期数学做出一个让步:因为年份并不总是在同一天开始,并且数据中的周数似乎并不总是与 SQL Server 返回的“常规”或 iso_week 匹配,我手动将周数视为自 1 月 1 日以来的 7 天区块。
我也看到这个:
START_W 和 FIRST_USE_W 是一年中的第几周(值可以从 1 到 52)。
一年有超过52周!
每年都会有部分周数53,其中至少有一两天。您需要能够解释这一点。
我想出了这个,甚至使用了交叉连接:
WITH ItemCity As (
SELECT Item, City, MIN( DATEADD(day, Start_W*7, DATEFROMPARTS(Start_Y, 1, 1)) ) As StartWeek
FROM Data
GROUP BY Item, City
),
ItemCityWeeks As (
SELECT Item,City, StartWeek
,Year(StartWeek) As Start_Y,datepart(week, StartWeek)-1 As Start_W
,YEAR(DATEADD(day, Weeks.num*7, StartWeek)) As First_Use_Y
,DATEPART(dayofyear, DATEADD(day, Weeks.num*7, StartWeek))/7 As First_Use_W
FROM ItemCity
CROSS JOIN ( VALUES (0), (1), (2), (3), (4)) Weeks(num)
)
SELECT icw.Item, icw.City
, icw.Start_Y, icw.Start_W, icw.First_Use_Y, icw.First_Use_W
, coalesce(d.value, 0) as Value
FROM ItemCityWeeks icw
LEFT JOIN Data d ON d.Item = icw.Item AND d.City = icw.City
and d.First_Use_Y = icw.First_Use_Y and d.First_Use_W = icw.First_Use_W
ORDER BY Item, City DESC
在这里查看它的工作原理:
另请注意,我的首次使用周比第一个城市的周要晚。我认为这是手动创建的样本结果中的一个错误,因为其他城市都以与 Start_W 同一周开始,而这个城市晚一周开始。