Question

I have a table in a Sybase SQL Anywhere database of the following structure (non-essential fields removed) that is populated by retail store registers opening and closing during a business day. Many days of history are kept in the table, and at the start of the day a register's status is assumed to be closed. "OPENTILL" signifies opening a register for business, "CLOSETILL" signifies closing it:

Register   Transaction_Date      Transaction_Time     Transaction_Type
1          2013-02-25            08:00:00.000         OPENTILL
2          2013-02-25            08:01:00.000         OPENTILL
3          2013-02-25            08:02:00.000         OPENTILL
2          2013-02-25            09:00:00.000         CLOSETILL
3          2013-02-25            09:01:00.000         CLOSETILL
2          2013-02-25            10:00:00.000         OPENTILL
4          2013-02-25            11:00:00.000         OPENTILL
3          2013-02-25            12:00:00.000         OPENTILL
2          2013-02-25            13:00:00.000         CLOSETILL
1          2013-02-25            14:00:00.000         CLOSETILL
3          2013-02-25            15:00:00.000         CLOSETILL
4          2013-02-25            20:00:00.000         CLOSETILL

This is only sample data and the actual number of registers goes beyond 4. The data I'm looking to extract is the maximum number of concurrently open registers per day, i.e. a table like this:

Date             Max_Concurrent_Registers
2013-02-25       14
2013-02-24       9
2013-02-23       12
2013-02-22       8

Is it possible to do this with nothing more than fairly basic Sybase SQL -- i.e. aggregate functions, "WITH x AS (...)", sub selects, but no cursors or stored procedures?

Thank you for any assistance

Was it helpful?

Solution

Funny, was involved in the discussion of a similar question the other day :)

SELECT transaction_date, MAX(concurrent_count)
  FROM ( SELECT transaction_date, Transaction_Time, Transaction_Type
               ,SUM( CASE WHEN transaction_type = 'OPENTILL' THEN 1 ELSE -1 END )
                OVER( PARTITION BY transaction_date
                      ORDER BY Transaction_Time ) AS concurrent_count
           FROM myTable
       ) x
   GROUP BY transaction_date

A sample run in Postgres:

postgres=# SELECT transaction_date, Transaction_Time, Transaction_Type
postgres-#                ,SUM( CASE WHEN transaction_type = 'OPENTILL' THEN 1 ELSE -1 END )
postgres-#                 OVER( PARTITION BY transaction_date ORDER BY Transaction_Time ) AS concurrent_count
postgres-#            FROM myTable;
 transaction_date | transaction_time | transaction_type | concurrent_count
------------------+------------------+------------------+------------------
 2013-02-25       | 08:00:00         | OPENTILL         |                1
 2013-02-25       | 08:01:00         | OPENTILL         |                2
 2013-02-25       | 08:02:00         | OPENTILL         |                3
 2013-02-25       | 09:00:00         | CLOSETILL        |                2
 2013-02-25       | 09:01:00         | CLOSETILL        |                1
 2013-02-25       | 10:00:00         | OPENTILL         |                2
 2013-02-25       | 11:00:00         | OPENTILL         |                3
 2013-02-25       | 12:00:00         | OPENTILL         |                4
 2013-02-25       | 13:00:00         | CLOSETILL        |                3
 2013-02-25       | 14:00:00         | CLOSETILL        |                2
 2013-02-25       | 15:00:00         | CLOSETILL        |                1
 2013-02-25       | 20:00:00         | CLOSETILL        |                0
(12 rows)


postgres=# SELECT transaction_date, MAX(concurrent_count)
postgres-#   FROM ( SELECT transaction_date, Transaction_Time, Transaction_Type
postgres(#                ,SUM( CASE WHEN transaction_type = 'OPENTILL' THEN 1 ELSE -1 END )
postgres(#                 OVER( PARTITION BY transaction_date ORDER BY Transaction_Time ) AS concurrent_count
postgres(#            FROM myTable
postgres(#        ) x
postgres-#    GROUP BY transaction_date;
 transaction_date | max
------------------+-----
 2013-02-25       |   4
(1 row)

OTHER TIPS

The optimal solution involves cumulative sums, but these are not supported in Sybase.

You can do the equivalent with a correlated subquery. The basic idea is that the number of open tills at any time is the sum of the number of open tills minus the sum of the number of closed tills. The final step is just to find the maximum:

select transaction_date, max(opentills)
from (select t.*,
             (select (sum(case when transaction_type = 'opentill' then 1 else 0 end) -
                      sum(case when transaction_type = 'closetill' then 1 else 0 end)
                     ) as NetOPens
              from transactions t2
              where t.transaction_date = t2.transaction_date
                    t2.transaction_time <= t.transaction_time
             ) as OpenTills
      from transactions t
    ) t
group by transaction_date
order by 1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top