You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Left join与window函数实现基于日期范围的SQL表列值修改?

解决方案

首先明确核心逻辑:要为表A的每一行,判断其class_id和prop_id在表B中是否存在对应的日期范围,能完全覆盖给定的年月(即当月第一天 ≤ date_from 且 date_to ≥ 当月最后一天)。如果存在则保留原prop_id,否则设为NULL。

方法一:分组过滤 + 左连接

这种方法逻辑直观,先预处理表B筛选出符合条件的(class_id, prop_id)对,再和表A关联:

-- 定义目标年月参数,替换为实际需求值
DECLARE @year INT = 2022, @month INT = 5;

-- 计算目标年月的起始和结束日期
WITH target_month AS (
    SELECT 
        DATEFROMPARTS(@year, @month, 1) AS start_date,
        EOMONTH(DATEFROMPARTS(@year, @month, 1)) AS end_date
),
-- 筛选表B中能覆盖目标年月的记录,按(class_id, prop_id)分组标记有效性
valid_prop AS (
    SELECT 
        b.class_id,
        b.prop_id,
        -- 只要该(class_id, prop_id)有一行满足条件,就标记为有效
        MAX(CASE 
            WHEN b.date_from <= tm.start_date AND b.date_to >= tm.end_date
            THEN 1 
            ELSE 0 
        END) AS is_valid
    FROM TableB b
    CROSS JOIN target_month tm
    GROUP BY b.class_id, b.prop_id
)
-- 左连接表A和有效记录,生成最终结果
SELECT 
    a.class_id,
    CASE WHEN vp.is_valid = 1 THEN a.prop_id ELSE NULL END AS prop_id
FROM TableA a
LEFT JOIN valid_prop vp 
    ON a.class_id = vp.class_id 
    AND a.prop_id = vp.prop_id;

方法二:结合窗口函数实现

如果需要用窗口函数(比如应对更复杂的分区逻辑),可以通过PARTITION BY对每个(class_id, prop_id)分区,计算该组内是否存在符合条件的记录:

DECLARE @year INT = 2022, @month INT = 5;

WITH target_month AS (
    SELECT 
        DATEFROMPARTS(@year, @month, 1) AS start_date,
        EOMONTH(DATEFROMPARTS(@year, @month, 1)) AS end_date
),
b_with_window AS (
    SELECT 
        b.class_id,
        b.prop_id,
        -- 窗口函数:按(class_id, prop_id)分区,判断该组是否有有效记录
        MAX(CASE 
            WHEN b.date_from <= tm.start_date AND b.date_to >= tm.end_date
            THEN 1 
            ELSE 0 
        END) OVER (PARTITION BY b.class_id, b.prop_id) AS has_valid_range
    FROM TableB b
    CROSS JOIN target_month tm
)
SELECT 
    a.class_id,
    -- 检查表B中是否存在对应有效记录
    CASE WHEN EXISTS (
        SELECT 1 
        FROM b_with_window bw 
        WHERE bw.class_id = a.class_id 
          AND bw.prop_id = a.prop_id 
          AND bw.has_valid_range = 1
    ) THEN a.prop_id ELSE NULL END AS prop_id
FROM TableA a;

结果验证(对应示例输入)

  • class_id=12:表B中aa_13的日期范围2022-02-15至2022-12-10完全覆盖2022-05,保留aa_13。
  • class_id=13:表B中无对应ab_21的记录,返回NULL。
  • class_id=22:表B中ac_11的起始日期2022-05-12晚于2022-05-01,无法覆盖整个5月,返回NULL。
  • class_id=53:表B中bb_32的结束日期2022-03-19早于2022-05-01,无法覆盖,返回NULL。
  • class_id=48:表B中ac_57的结束日期2022-05-07早于2022-05-31,无法覆盖整个5月,返回NULL。

两种方法均可得到预期结果,可根据实际场景选择。

内容的提问来源于stack exchange,提问作者user177196

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 13:09:28