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

如何不使用IF EXISTS实现日期条件下的订单数据筛选需求

Alright, let's tackle this problem. We need to fetch either one row per mobile number from the Order table when the current date falls within the date range defined in the settings table, or all rows if it's outside that range—without using IF EXISTS.

First, let's recap the sample tables and data we're working with:

Sample Table Setup

DECLARE @settings TABLE(id INT, Gateway NVARCHAR(80), startDateTime DATETIME, endDateTime DATETIME);
INSERT INTO @settings VALUES (1,'com1','2018-05-1 00:00:00.000','2018-05-30 23:59:59.000');

DECLARE @Order TABLE(id INT, Gateway NVARCHAR(80), mobile NVARCHAR(80), [Date] DATETIME);
INSERT INTO @Order VALUES 
(1,'com1','222088','2018-05-17 10:15:54.047'),
(2,'com1','212409','2018-05-17 11:20:22.047'),
(3,'com1','227263','2018-05-17 12:53:42.047'),
(4,'com1','222088','2018-05-17 13:48:32.047'),
(5,'com1','212409','2018-05-17 14:43:12.047'),
(6,'com1','212409','2018-05-17 15:27:11.047'),
(7,'com1','222088','2018-05-18 15:15:54.047');

Approach 1: CASE Statement with ROW_NUMBER()

This method uses a CASE inside the PARTITION BY clause of ROW_NUMBER() to dynamically adjust how we group rows. When we're in the date range, we group by mobile to get one row per number; when outside, we group by a unique value (like id) so every row gets a row number of 1.

SELECT o.id, o.Gateway, o.mobile, o.[Date]
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER(
            PARTITION BY 
                CASE WHEN EXISTS(SELECT 1 FROM @settings WHERE GETDATE() BETWEEN startDateTime AND endDateTime)
                     THEN mobile
                     ELSE CAST(id AS NVARCHAR(20)) -- Unique per row to retain all records
                END
            ORDER BY [Date] DESC -- Adjust this to pick which row to keep per mobile (e.g., latest here)
        ) AS rn
    FROM @Order o
) AS ranked
WHERE rn = 1;

Note: Adjust the ORDER BY inside ROW_NUMBER() if you want to pick a different row per mobile (like the earliest entry instead of the latest).

Approach 2: CTE for Range Status + Filter Logic

We first create a CTE to check if we're inside the settings date range, then cross-join that status with the Order table. We use the status to decide whether to filter for one row per mobile or keep everything.

WITH RangeStatus AS (
    SELECT 
        CASE WHEN GETDATE() BETWEEN startDateTime AND endDateTime THEN 1 ELSE 0 END AS IsInRange
    FROM @settings
)
SELECT o.id, o.Gateway, o.mobile, o.[Date]
FROM @Order o
CROSS JOIN RangeStatus rs
WHERE 
    (rs.IsInRange = 1 AND 
     ROW_NUMBER() OVER(PARTITION BY o.mobile ORDER BY o.[Date] DESC) = 1)
    OR rs.IsInRange = 0
ORDER BY o.mobile, o.[Date];

This approach keeps the range check separate, making the logic easier to read and modify later.

Approach 3: TOP 1 WITH TIES + Dynamic Partitioning

Leverage the TOP 1 WITH TIES feature, which returns all rows that have the same row number as the top row. We use the same dynamic partitioning trick as Approach 1 to get either one row per mobile or all rows.

SELECT TOP 1 WITH TIES
    o.id, o.Gateway, o.mobile, o.[Date]
FROM @Order o
ORDER BY 
    ROW_NUMBER() OVER(
        PARTITION BY 
            CASE WHEN EXISTS(SELECT 1 FROM @settings WHERE GETDATE() BETWEEN startDateTime AND endDateTime)
                 THEN mobile
                 ELSE o.id
            END
        ORDER BY o.[Date] DESC
    );

This is the most concise method—great if you prefer shorter, more compact code.

All three approaches avoid using IF EXISTS and will return the expected results: one row per mobile when in the date range, all rows when outside.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:05:07