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

申根区180天/90天停留规则SQL计算方案问询

申根区停留天数计算:通用SQL实现方案

欧盟申根协议允许约50个国家的游客在任意180天周期内最多停留90天。现假设2023年2月1日入境申根区,停留至2023年5月1日(共90天),需计算2023年底前每日可再次入境的停留天数。

已知Excel计算结果:2023年9月1日返回时,过去180天(起始日为2023年3月5日)内累计停留59天,该数值将保持至2023年10月30日,之后停留天数均来自本次9月1日的入境。

现有实现通过硬编码日期创建了包含2年日期的临时表#Vaca,标记每日境内外状态,但需要通用SQL语句支持以下需求:

  • 规划最早返回日期(如2023年8月1日)
  • 给定指定返回日,计算要求的离境日期

现有硬编码实现代码

DROP TABLE IF EXISTS #Vaca
CREATE TABLE #Vaca
(
    VacationDate date
    ,[Location] nvarchar(100)
    ,InEu int
)

DECLARE @n int = 0
        ,@StartDate date = N'2022/06/01'

WHILE @n < 730
BEGIN
    INSERT INTO #Vaca
    (
        VacationDate
        ,[Location]
        ,InEu
    )
    VALUES (@StartDate
            ,CASE WHEN @StartDate BETWEEN N'2023/02/01' and N'2023/05/01'THEN N'EU'
                    WHEN @StartDate BETWEEN N'2023/09/01' and N'2023/11/29'THEN N'EU'
                    ELSE N'Outside EU'
            END
            ,CASE WHEN @StartDate BETWEEN N'2023/02/01' and N'2023/05/01'THEN 1
                    WHEN @StartDate BETWEEN N'2023/09/01' and N'2023/11/29'THEN 1
                    ELSE 0
            END
    )

    SET @n += 1
    SET @StartDate = DATEADD(DAY, 1, @StartDate)
END

SELECT  v.[Location]
        ,v.VacationDate
        ,SUM(v.InEu) OVER    (   ORDER BY    v.VacationDate ASC
                                    ROWS    179 PRECEDING
                                ) AS Test

FROM    #Vaca AS v

WHERE   1 = 1

GROUP BY    v.VacationDate
            ,v.[Location]
            ,v.InEu

ORDER BY    2 ASC

通用化SQL解决方案

1. 参数化存储停留记录与动态生成日期表

替换硬编码逻辑,用临时表存储已知停留区间,动态生成所需分析日期范围:

-- 清理临时表
DROP TABLE IF EXISTS #KnownStays;
DROP TABLE IF EXISTS #DateRange;

-- 存储已知的申根区停留记录(可灵活添加/修改)
CREATE TABLE #KnownStays (
    StayStart DATE,
    StayEnd DATE
);

-- 插入示例停留记录
INSERT INTO #KnownStays (StayStart, StayEnd)
VALUES 
    ('2023-02-01', '2023-05-01'),  -- 第一次90天停留
    ('2023-09-01', '2023-11-29');  -- 第二次停留(按需调整)

-- 定义分析日期范围:从最早停留前180天到2023年底
DECLARE @AnalysisStart DATE = (SELECT DATEADD(DAY, -180, MIN(StayStart)) FROM #KnownStays);
DECLARE @AnalysisEnd DATE = '2023-12-31';

-- 递归生成连续日期表
WITH DateCTE AS (
    SELECT @AnalysisStart AS VacationDate
    UNION ALL
    SELECT DATEADD(DAY, 1, VacationDate)
    FROM DateCTE
    WHERE VacationDate < @AnalysisEnd
)
SELECT 
    VacationDate,
    CASE 
        WHEN EXISTS (SELECT 1 FROM #KnownStays ks WHERE dc.VacationDate BETWEEN ks.StayStart AND ks.StayEnd) 
        THEN 'EU' 
        ELSE 'Outside EU' 
    END AS Location,
    CASE 
        WHEN EXISTS (SELECT 1 FROM #KnownStays ks WHERE dc.VacationDate BETWEEN ks.StayStart AND ks.StayEnd) 
        THEN 1 
        ELSE 0 
    END AS InEu
INTO #DateRange
FROM DateCTE
OPTION (MAXRECURSION 0); -- 支持超过100天的递归生成

2. 计算每日180天周期内停留数据

用窗口函数计算每个日期的累计停留天数及剩余可停留天数:

SELECT 
    VacationDate,
    Location,
    InEu,
    SUM(InEu) OVER (
        ORDER BY VacationDate ASC
        ROWS BETWEEN 179 PRECEDING AND CURRENT ROW
    ) AS TotalStayIn180Days,
    90 - SUM(InEu) OVER (
        ORDER BY VacationDate ASC
        ROWS BETWEEN 179 PRECEDING AND CURRENT ROW
    ) AS RemainingAllowedDays
FROM #DateRange
ORDER BY VacationDate ASC;

3. 查询指定日期后最早可返回日期

例如,查找2023年8月1日之后最早可入境且有剩余停留额度的日期:

SELECT TOP 1 
    VacationDate AS EarliestReturnDate,
    RemainingAllowedDays
FROM (
    SELECT 
        VacationDate,
        90 - SUM(InEu) OVER (
            ORDER BY VacationDate ASC
            ROWS BETWEEN 179 PRECEDING AND CURRENT ROW
        ) AS RemainingAllowedDays
    FROM #DateRange
    WHERE VacationDate >= '2023-08-01'
) t
WHERE RemainingAllowedDays > 0
ORDER BY VacationDate ASC;

4. 给定返回日期,计算最晚离境日期

假设指定返回日为2023-09-01,计算符合规则的最晚离境日期:

DECLARE @ReturnDate DATE = '2023-09-01';

WITH StaySimulation AS (
    SELECT 
        VacationDate,
        -- 模拟从返回日开始入境,标记当日及后续为境内状态
        CASE WHEN VacationDate >= @ReturnDate THEN 1 ELSE InEu END AS SimulatedInEu,
        -- 计算模拟后的180天累计停留天数
        SUM(CASE WHEN VacationDate >= @ReturnDate THEN 1 ELSE InEu END) OVER (
            ORDER BY VacationDate ASC
            ROWS BETWEEN 179 PRECEDING AND CURRENT ROW
        ) AS SimulatedTotalStay
    FROM #DateRange
    WHERE VacationDate >= @ReturnDate
)
SELECT MAX(VacationDate) AS LatestDepartureDate
FROM StaySimulation
WHERE SimulatedTotalStay <= 90;

优化说明

  • 参数化配置:所有停留记录和分析范围通过临时表/参数定义,无需修改核心逻辑
  • 高效日期生成:递归CTE比WHILE循环插入更高效,支持任意长度的日期范围
  • 灵活查询:快速支持最早返回日、最晚离境日等多样化需求
  • 可维护性:逻辑清晰,新增停留记录只需插入#KnownStays即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:44:52