I want to write a query which returns all rows until the sum of one of the columns value reaches a certain value.
For example in the table below:
Here's a way to do it without a stored procedure:
SET @msum := 0;
SELECT t1.*
FROM (
SELECT m.*,
(@msum := @msum + m.meetings) AS cumulative_meetings
FROM meetings m
ORDER BY m.date ASC
) t1
WHERE t1.cumulative_meetings <= 7;
Hemant you do not state the RDBMS that use. Here is a script in t-sql that you can use in order to solve your problem.
DECLARE @numberToReach INT;
SET @numberToReach = 10; --you can change this
DECLARE @date DATETIME;
DECLARE @etc VARCHAR(20);
DECLARE @meeting INT;
DECLARE @temp_sum INT;
CREATE TABLE #tempTable
(
Dates DATETIME,
Etcs VARCHAR(20),
Meeting INT,
)
DECLARE tempcursor CURSOR FOR
SELECT *
FROM YourTABLENAME
OPEN tempcursor;
FETCH NEXT FROM tempcursor INTO @date, @etc, @meeting;
WHILE(@@FETCH_STATUS = 0)
BEGIN
SET @temp_sum = @temp_sum + @meeting;
IF @temp_sum < @numberToReach
BEGIN
INSERT INTO #tempTable
(
Dates,
Etcs,
Meeting
)
VALUES
(
@date,
@etc,
@meeting
)
FETCH NEXT FROM tempcursor INTO @date, @etc, @meeting;
END
END
SELECT * FROM #tempTable
CLOSE tempcursor
DEALLOCATE tempcursor
DROP TABLE #tempTable
If you are using SQL Server, then use CROSS APPLY.
In Oracle, I think you can use the SUM analytic function. You can refer here: http://www.adp-gmbh.ch/ora/sql/analytical/sum.html
Here's an ugly way:
SELECT *
FROM meetings m1
WHERE (SELECT SUM(m2.Meeting)
FROM meetings m2
WHERE m2.DATE < m1.DATE OR (m2.DATE = m1.DATE AND m2.ETC >= m1.ETC)) <= 7
The ordering is based on DATE
first, then ETC
in descending order, since that seems to be what we have to go on. Note that if that is not unique, you will get the wrong result.
This one outperforms all.
SET @runningTotal=0;
SELECT
O.Id,
O.Type,
O.MyAmountCol,
@runningTotal + O.MyAmountCol as 'RunningTotal',
@runningTotal := @runningTotal + O.MyAmountCol
FROM Table1 O
HAVING RunningTotal <=7;
SQL Fiddle
Take a look at execution plans for both queries.