SQL 搜索多个日期范围内出现的交易类型

Posted

技术标签:

【中文标题】SQL 搜索多个日期范围内出现的交易类型【英文标题】:SQL search for occurrences of transaction types within multiple date ranges 【发布时间】:2020-10-13 21:04:39 【问题描述】:

我有以下表格:

CREATE TABLE Users
(
    UserID INT,
    UserName VARCHAR(100)
)
CREATE TABLE Trans
(
    UserID INT,
    TransID INT,
    TransTypeID INT,
    TransDate DATETIME,
    TransAmount DECIMAL(15,2)
)
CREATE TABLE TransType
(
    TransTypeID INT,
    TransTypeName VARCHAR(10)
)

为了简单起见,TransType 表中只有 2 个条目:

    收入 费用

我正在寻找是否有 3 次或更多类型为收入的交易和 3 次或更多类型为费用的交易在特定时间段内发生在特定用户的日期范围内。

例如,我的搜索可能有以下变量:

DECLARE @StartDate DATETIME = '2018-06-30'
DECLARE @EndDate DATETIME = '2019-09-30'
DECLARE @SearchPeriodMonths INT = 6

我当前的解决方案从 @StartDate 到 @EndDate 以 6 个月的块(由 @SearchPeriodMonths 定义)搜索,如果存在 3 个或更多的收入和费用交易,则需要在表中返回。此解决方案效率不高,并且涉及使用游标。我希望有更好的方法。

CREATE TABLE #Results
(
    UserID int,
    StartDate DATETIME,
    EndDate DATETIME,
    Message VARCHAR(255)
)

DECLARE @UserID INT

DECLARE crUser CURSOR FOR
SELECT UserID
FROM Users

OPEN crUser
FETCH NEXT FROM crUser INTO @UserID

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @DateCount TABLE(UserID INT, StartDate DATETIME, EndDate DATETIME, IncomeCount INT, ExpenseCount INT)

    WHILE(@StartDate < @EndDate)
    BEGIN
        SELECT @StartDate = DATEADD(DAY, 1, @StartDate)
        INSERT INTO @DateCount
        SELECT
            @UserID AS UserID,
            @StartDate AS StartDate,
            DATEADD(MONTH, @SearchPeriodMonths, @StartDate) AS EndDate, 
            (SELECT COUNT(*) FROM Trans WHERE TransTypeID = 1 AND UserID = @UserID 
                AND TransDate BETWEEN @StartDate and DATEADD(MONTH, @SearchPeriodMonths, @StartDate) 
                AS IncomeCount,
            (SELECT COUNT(*) FROM Trans WHERE TransTypeID = 2 AND UserID = @UserID 
                AND TransDate BETWEEN @StartDate and DATEADD(MONTH, @SearchPeriodMonths, @StartDate) 
                AS ExpenseCount
    END

    INSERT INTO #Results
    SELECT
      @UserID AS UserID,
      MIN(StartDate) AS StartDate,
      MAX(EndDate) AS EndDate,
      '3 or more Income and Expense transaction types occur in a 6 month period between ' 
        + convert(varchar, min(StartDate), 106) + ' and ' 
        + convert(varchar, max(EndDate), 106) AS WarningMessage
    FROM @DateCount
    WHERE IncomeCount > 2 AND ExpenseCount > 2

    FETCH NEXT FROM crUser INTO @UserID
END
CLOSE crUser
DEALLOCATE crUser

-- Output query
SELECT *
FROM #Results

END

我仅限于在 SQL Server 2008 R2 中执行此操作。有没有更有效的方法来做到这一点而不涉及使用游标?

【问题讨论】:

【参考方案1】:

我正在寻找是否有 3 次或更多类型为收入的交易和 3 次或更多类型为费用的交易发生在特定用户的特定日期范围内的特定时间段内。

使用聚合!

select userid
from trans
where transdate between @startdate and dateadd(month, @SearchPeriodMonths, @StartDate)
group by userid
having sum(case when transtypeid = 1 then 1 else 0 end) >= 3 and
       sum(case when transtypeid = 2 then 1 else 0 end) >= 3;

【讨论】:

以上是关于SQL 搜索多个日期范围内出现的交易类型的主要内容,如果未能解决你的问题,请参考以下文章

sql 在日期范围内搜索

SQL Server 在日期范围内聚合

SQL在where语句中使用日期范围的选择子查询来确定该日期范围内的最大值

SQL从日期范围内的同一表中的不同记录中获取多个项目的总和(ORACLE)

sql 查询时间、日期范围内的数据

SQL 如何查询日期在一定范围内的数据