1

Want to select only 2 latest records from orders table, where count of AGENT_CODE is less than 3,

Guide me to do this in efficient way, I don’t want to go through all the records whenever this query runs.

My SQL query is something like this but does not work

SELECT ORD_NUM, ORD_DATE
FROM ORDERS
WHERE ADVANCE_AMOUNT>50
AND ( SELECT ORD_DATE, COUNT( AGENT_CODE )
    FROM ORDERS
    HAVING COUNT( AGENT_CODE ) < 3
    ORDER BY ORD_DATE DESC LIMIT 5;)
ORDER BY ORD_DATE DESC LIMIT 2;

My ORDERS table is

CREATE TABLE `orders` (
  `ORD_NUM` int(11) NOT NULL,
  `ADVANCE_AMOUNT` int(11) NOT NULL,
  `ORD_DATE` date NOT NULL,
  `CUST_CODE` varchar(10) NOT NULL,
  `AGENT_CODE` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `orders` (`ORD_NUM`, `ADVANCE_AMOUNT`, `ORD_DATE`, `CUST_CODE`, `AGENT_CODE`) VALUES
(1, 3500, '2017-08-15', 'C00002', 'A08'),
(2, 2500, '2017-09-16', 'C00003', 'A08'),
(3, 500, '2017-07-20', 'C00023', 'A08'),
(4, 4000, '2017-09-16', 'C00007', 'A10'),
(5, 1500, '2017-09-23', 'C00008', 'A04'),
(6, 2500, '2017-07-30', 'C00025', 'A10'),
(7, 4000, '2017-02-15', 'C00008', 'A11'),
(8, 1500, '2017-05-15', 'C00021', 'A11'),
(9, 2500, '2017-12-18', 'C00025', 'A11');

My intention is to select these

   ORD_NUM ORD_DATE
---------- ---------
       5   2017-09-23
       4   2017-09-16
0

4 Answers 4

1

You may try with this:

SELECT ORD_NUM, ORD_DATE
FROM ORDERS
WHERE ADVANCE_AMOUNT>50
group by ord_num, ord_date
having count(agent_code)<3
ORDER BY ORD_DATE DESC LIMIT 2;

EDIT Sorry, try with this one:

SELECT ORD_NUM, ORD_DATE
FROM ORDERS as a
WHERE ADVANCE_AMOUNT>50
and (select count(agent_code)
     from orders as b
     where a.agent_code=b.agent_code)<3
ORDER BY ORD_DATE DESC LIMIT 2;
Sign up to request clarification or add additional context in comments.

6 Comments

As I wrote to the answer belove, it may "work" in terms of the question "per se" I mean that DMP asked only for the ord_num 5 and 5. But as belove I believe the question is regarding more about the "logic" of have AGENT_CODE that are < 3. In these terms that "LIMIT 2" is not just filtering any other record present in n instance, where n = 1, 2 as for example (10, 4000, '2017-09-16', 'C00007', 'A12');. indeed have a look at what your code does : sqlfiddle.com/#!9/06d3ec/22 and what instead I mean (without the order by ) sqlfiddle.com/#!9/06d3ec/21
sorry my bad. The query that works in a more general case should be without LIMIT and Group by as well as
@Carmine Tambascia The LIMIT 2 it's important for DMP just because he is asking for the last 2, not for all. And if you group by agent_code, you lose the information about the date
indeed I did not post an answer as I believe yours is complete as well as. My comment came more thinking about what really DMP want. As you wrote, he he want the last 2 then yours is perfect, nevertheless instead if his implicit question was about any group agent_code > 3, then that's way I made my comment. Also regarding the group you are right, indeed see my previous comment
Actually I checked again and I added a record with only one instance, and indeed that can be "filtered" only with a last group by as from here sqlfiddle.com/#!9/06d3ec/36. But again not limit. I am not sure he is asking only for the "last" 2 in terms of date, otherwise then also the record with 'A08' should be included. Instead what I understood is that he want those where agent_code is < 3 in a performance way, without to touch all record(but I will stay to the logic and then resolve the performance, if possible)
|
1

Join with a subquery that gets the agent codes with count less than 3:

SELECT ORD_NUM, ORD_DATE
FROM ORDERS AS o
JOIN (SELECT agent_code
      FROM orders
      GROUP BY agent_code
      HAVING COUNT(*) < 3) AS a
ON o.agent_code = a.agent_code
WHERE ADVANCE_AMOUNT>50
ORDER BY ORD_DATE DESC
LIMIT 2

DEMO

5 Comments

But in case there will be a more general case as I guess, like another record with coun<3 as (10, 4000, '2017-09-16', 'C00007', 'A12'), then the LIMIT 2 statment will just ignore it. better add before the last order by another GROUP BY o.AGENT_CODE
What's wrong with ignoring it? The question says that only the 2 most recent orders should be returned, not just one per agent.
Well in terms of what I got it is not about the most recent, otherwise 'A08' with ord_num =2 should be also picked. Instead my understanding is that he want those with count< 3. Your logic works of course with his example, but adding another record with only one instance, then it will fail, as from here sqlfiddle.com/#!9/06d3ec/36. This only because we provide answer not only for the sake of the question, but for future reference.
@CarmineTambascia A08 has count = 3, ord_num = 1, 2, 3, so none of them are included because it should only include agents with less than 3 orders.
@CarmineTambascia Maybe what you're talking about is what to do if there are ties in the most recent N rows that are selected? LIMIT 2 will ignore some of them randomly, which might not be desired.
0

Keep in mind that whatever you put after an AND operator must be a boolean value:

AND (whatever condition with true/false value)

If you do not want go through all the records whenever this query runs, use an auxiliary table with entries that match the condition

HAVING COUNT( AGENT_CODE ) < 3

Use a trigger to update this aux table whenever you make an insert value to the original table. https://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html

Comments

-1
WITH CTE AS

(  
    SELECT *
    FROM ORDERS
    WHERE ADVANCE_AMOUNT>50
)

SELECT ORD_NUM, ORD_DATE FROM CTE
GROUP BY AGENT_CODE
HAVING COUNT(*) < 3
ORDER BY ORD_DATE DESC LIMIT 2;

2 Comments

MySQL doesn't have CTE.
While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.