Sample Header Ad - 728x90

Variable only resets per row when query has a static IN condition

0 votes
0 answers
27 views
I have a complicated query. I have a bunch of users. I have a ledger of debits and credits. I want to filter a user's subscribers by how long the subscribers have been negative. To do that I find negative subscribers for a given user, get each subscriber's transactions in reverse order, and work backwards until the subscriber's balance is ≥ 0 to find how long ago that was. The query works only if I take the list of subscriber IDs the query returns and add them into the WHERE clause. ##### The Query
-- Return just the info we want
SELECT subscriber_id,
       balance,
       days_negative,
       DATE_SUB(CURRENT_DATE, INTERVAL days_negative DAY) AS days_since
FROM (
    -- Reset @balanced for each subscriber
    SELECT r.subscriber_id,
           balance,
           (@balanced := FALSE),
           (
               -- get date of last transaction before balance >= 0
               SELECT DATEDIFF(CURRENT_DATE, MIN(transaction_time))
               FROM (
                   -- work backwards until balance >= 0
                   SELECT *,
                          ROUND(balance, 2),
                          ROUND(balance - running_total, 2),
                          (@balanced := @balanced OR balance - running_total + amount >= 0) AS balance_reached
                   FROM (
                       -- get transactions with running total
                       SELECT t.transaction_id,
                              t.transaction_time,
                              t.subscriber_id,
                              t.amount,
                              t.category,
                              SUM(t.amount) OVER w AS running_total
                       FROM transactions t
                       WHERE t.subscriber_id = r.subscriber_id
                         AND t.void = 0
                       WINDOW w AS (ORDER BY transaction_time DESC, transaction_id DESC)
                   ) with_running_total
               ) with_balance_reached
               WHERE balance_reached = 0
           ) AS days_negative
    FROM subscribers r
             INNER JOIN user_subscriber_linker usl USING (subscriber_id)
             INNER JOIN subscriber_balance b USING (subscriber_id)
    WHERE usl.user_id = 12345
      AND r.subscriber_id IN (987, 654, 321)
      AND r.void = 0
      AND b.balance < 0
    GROUP BY subscriber_id
) with_each;
This query gives me a result like this: | renter\_id | balance | days\_negative | negative\_since | | :--- | :--- | :--- | :--- | | 987 | -5998.90 | 98 | 2024-08-01 | | 654 | -2000.00 | 62 | 2024-09-06 | | 321 | -3774.20 | 79 | 2024-08-20 | When I remove the line AND r.subscriber_id IN (987, 654, 321), I get this: | renter\_id | balance | days\_negative | negative\_since | | :--- | :--- | :--- | :--- | | 987 | -5998.90 | 98 | 2024-08-01 | | 654 | -2000.00 | null | null | | 321 | -3774.20 | null | null | The fact that the first row is correct leads me to believe @balanced isn't being set for each row. I tried using joins (JOIN (SELECT @balanced := FALSE)) to set the var but that hasn't worked either. How do I get the query to work?
Asked by tvanc (101 rep)
Nov 7, 2024, 07:57 PM
Last activity: Nov 7, 2024, 08:43 PM