There are two tables:
CREATE TABLE STORE (
ID INTEGER NOT NULL,
MEDICINE_ID INTEGER NOT NULL,
SHIPMENT_ID INTEGER NOT NULL,
PACKAGE_ID INTEGER NOT NULL,
QUANTITY INTEGER NOT NULL);
CREATE TABLE ORDERS (
ID INTEGER NOT NULL,
CLIENT_ID INTEGER NOT NULL,
STORE_ITEM_ID INTEGER NOT NULL,
QUANTITY INTEGER NOT NULL,
ORDERDATE DATE NOT NULL,
STATE INTEGER DEFAULT 1 NOT NULL);
I’ve wrote here only fields, no generators, triggers, key e.t.c.
The next view selects the most popular medicines per date:
CREATE VIEW ORDERS_STORE_QTY
AS
SELECT
O1.ORDERDATE,
S1.MEDICINE_ID,
SUM(O1.QUANTITY) AS QTY
FROM ORDERS O1
INNER JOIN STORE S1 ON (S1.ID = O1.STORE_ITEM_ID)
WHERE O1.STATE=5 /* the closed order */
GROUP BY O1.ORDERDATE, MEDICINE_ID
ORDER BY O1.ORDERDATE, SUM(O1.QUANTITY) DESC
Then I do left join of the view with itself and in condition compare summary quantity:
SELECT T1.ORDERDATE, T1.MEDICINE_ID, T1.QTY
FROM ORDERS_STORE_QTY T1
LEFT OUTER JOIN ORDERS_STORE_QTY T2
ON (
T1.ORDERDATE = T2.ORDERDATE
AND
T2.QTY > T1.QTY
)
GROUP BY T1.ORDERDATE, T1.MEDICINE_ID, T1.QTY
HAVING COUNT(T2.MEDICINE_ID) < 5
ORDER BY T1.ORDERDATE, T1.QTY DESC
If all the summary quantity per day would be different, I had no problem.
My task is to limit “best” medicines to five per day, but there are repeating quantities sometimes, so instead of sequence
0, 1, 2, 3, 4
I got:
0, 1, 2, 2, 2, 3, 4, 5 for example.
How can I change the query (I would prefer do not use generators and also do not use denormalization) to really limit the count of rows?
All the code is close to pure SQL (I do hope so) and written for Firebird 2.5.
I believe you can change the on clause in the self join to:
What this does is to eliminate the ties by imposing a strict ordering — first by quantity and then by medicine id.
Oh, if you used a database that supported window functions (row_number()), this would be much easier 😉