views:

44

answers:

4

Consider a table like this:

| txn_id | account_id

I'd like to do a single query that will get me all txn_ids for all transactions where the transaction is not the most recent (highest txn_id) for the account_id .

The database is MySQL 5.1, so that might imply some limitations around sub-selects.

+2  A: 

If I understand right

SELECT txn_id
  FROM table
 WHERE txn_id <> (SELECT MAX(txn_id) FROM table WHERE account_id = 123456)
   AND account_id = 123456
Infinity
No. At minimum, you would need to qualify the sub-select with 'WHERE account_id = 123456'. See the answer by artemb which does this.
Jonathan Leffler
D'oh.. absolutely. I fixed my answer
Infinity
+1  A: 

Try something like this:

select txn_id, account_id
order by txn_id desc
limit 1,18446744073709551615;
Andrew Hare
+1. The best choice if you have no order preferences. If you do, gotta go with sub-selection
artemb
Can you explain how this works - because I don't see why it works at all.
Jonathan Leffler
It sorts the records on txn_id in reverse order meaning the highest txn_id will go to the top. Then it returns all the records beginning from the second one, effectively skipping the record with the highest txn_id
artemb
@artemb: okay - thanks for the explanation. I'm not clear how the proposed SQL answers the question, but at least the query is clearer. (I see from the manuals that LIMIT starts offsets at zero, rather than using 1 as most of the rest of SQL does; that was part of my confusion.)
Jonathan Leffler
A: 
select txn_id from table 
where account_id = 123 and 
txn_id < (select max(txn_id) from table where account_id = 123)
artemb
That's fine for one account at a time. I think the question is seeking to execute the equivalent of that statement for each account_id value.
Jonathan Leffler
+2  A: 

Given the requirement:

I'd like to do a single query that will get me all txn_ids for all transactions where the transaction is not the most recent (highest txn_id) for the account_id.

it seems that answers which give you transaction IDs for a single account at a time are missing the point of the query.

To get the list of transaction IDs that must be retained (or ignored) we can write:

SELECT MAX(txn_id) AS max_txn_id, account_id
  FROM UnnamedTable
 GROUP BY account_id;

Now we need to get the list of transaction IDs not found in that list. That isn't wholly straight-forward:

SELECT txn_id, account_id
  FROM UnnamedTable
 WHERE txn_id NOT IN
             (SELECT max_txn_id
                FROM (SELECT MAX(txn_id) AS max_txn_id, account_id
                        FROM UnnamedTable
                       GROUP BY account_id
                     )
             )

Anyway, that works OK with IBM Informix Dynamic Server 11.50 and the table and data below:

create table unnamedtable(txn_id integer not null, account_id integer not null);
insert into unnamedtable values(1, 12);
insert into unnamedtable values(2, 12);
insert into unnamedtable values(3, 12);
insert into unnamedtable values(4, 13);

yielding the results:

1    12
2    12
Jonathan Leffler