【问题标题】:T-SQL date ranges using dynamic variables in loop在循环中使用动态变量的 T-SQL 日期范围
【发布时间】:2018-07-06 17:29:44
【问题描述】:

我有一个包含事务、时间戳和用户的表。

CREATE TABLE [dbo].[Transactions]
(
    [transaction_ts] [datetime] NULL,
    [user_id] [bigint] NULL,
    [transaction_id] [bigint] NULL,
    [item] [varchar](50) NULL
)

对于每个user_id,我需要选择他们在第一次交易和 72 小时后进行的所有交易。

--get first and last timestamps for range
DROP TABLE IF EXISTS #first;

SELECT mt.transaction_ts as first_trans,mt.user_id 
INTO #first
FROM Transactions mt 
INNER JOIN
    (SELECT user_id, MIN(transaction_ts) MinDate
     FROM Transactions
     GROUP BY user_id) t ON mt.user_id = t.user_id AND mt.transaction_ts = t.MinDate;

ALTER TABLE #first
ADD first_trans_plus_72 datetime;

UPDATE #first 
SET first_trans_plus_72 = DATEADD(hour, 72, first_trans)

--loop through user_id and select ranges using variables
DECLARE @Table TABLE (user_id bigint, Id int identity(1,1));

INSERT INTO @Table 
    SELECT DISTINCT user_id 
    FROM #first;

DECLARE @max int;
DECLARE @SQL VARCHAR(MAX);
DECLARE @user_id VARCHAR(max);
DECLARE @first VARCHAR(max);
DECLARE @first_trans_plus_72 VARCHAR(max);
DECLARE @id int = 1;

SELECT @max = MAX(Id) FROM@Table;

WHILE (@id <= @max)
BEGIN
    SELECT @user_id = user_id FROM @Table WHERE Id = @id
    SELECT @first = first_trans FROM #First WHERE user_id = @user_id
    SELECT @first_trans_plus_72 = first_trans_plus_72 FROM #First WHERE user_id = @user_id
    SET @SQL = 'select * from Transactions 
                where transaction_ts between ' + @first + ' and ' + @first_trans_plus_72 + ' 
                and user_id = ' + @user_id + ';'
    PRINT(@SQL)
    EXEC(@SQL)
    SET @id = @id +1
END

这会产生正确的逻辑 sql,但日期时间变量是字符串,因此查询会出错。我尝试将日期时间变量(@first@first_trans_plus_72 设置为 datetime 但这导致转换错误。

有没有更简单的方法来做到这一点?

【问题讨论】:

    标签: sql sql-server tsql while-loop


    【解决方案1】:

    既然可以使用简单查询,为什么还要为此使用循环?

    select t.*
    from (select t.*, min(transaction_ts) over (partition by user_id) as min_tts
          from transactions t
         ) t
    where t.transaction_ts <= dateadd(hour, 72, min_tts);
    

    一般来说,最好使用基于集合的操作来编写代码。它更简单,性能也好得多。

    您可以将其合并到更新中,但我认为没有必要。以上选择交易。您可以使用group by user_id 对它们进行汇总——比如对它们进行计数或对值求和。

    【讨论】:

    • 答案是我很不擅长SQL。另外我不知道那个分区的东西 - 非常方便,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2013-10-10
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2013-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多