Reputation: 10354
I need a select statement which will interrogate a list of totals and work out whether an adding combination exists within the result set that is equal to a local variable.
Example:
create table #mytemptable
(
totals Decimal (19,2)
)
insert into #mytemptable (totals)
values (57.83),
(244.18),
(239.23),
(227.79),
(563.12)
select *
from #mytemptable
I would now like to check if any combination(s) within the result when added will equal
285.62
Also, it would be nice if there were multiple instances where totals could be added to equal my variable then this would be handled and displayed in an appropriate fashion.
Upvotes: 2
Views: 140
Reputation: 3400
If you are willing to add an identity column to your table the following CTE solution will work for you:
WITH SumOfPermutations AS
(
SELECT
CONVERT(decimal(15,2), 0) SummedTotals,
0 id
UNION ALL
SELECT
CONVERT(decimal(15,2), A.SummedTotals + B.totals),
B.ID
FROM
SumOfPermutations A
INNER JOIN myTempTable B ON A.ID < B.ID AND A.SummedTotals + B.Totals <= 285.62
WHERE
A.SummedTotals + B.totals <= 285.62
)
SELECT
COUNT(*)
FROM
SumOfPermutations
WHERE
SummedTotals = 285.62
However be advised if you have a large number of small values the performance will degrade massively. This is because of the fact that once a permutation's sum is above 285.62 it is not included any more. If you have lots of small small values then you will have lots of permutations that have a large number of values before they reach the 285.62 threshold. If your real data is distibuted similarly to the example data you gave, this should work well and quickly.
If you expect that the most numbers from your table that can be summed to a value below your 285.62 is of the order of 10, you should be OK. However if you have 20 values in your table below 30.0 you will probably have issues with this.
Upvotes: 0
Reputation: 5542
A bit convoluted but here it goes:
Basically my aim is to generate a dynamic query where one column will identify the value (first value on column A, second on column B, etc) and finally a column with the total.
After that we can do a group by with cube, which will sum all the permutations of values grouping them by the different columns. view example
The final result will show something like:
Total A B C D E
285.62 NULL NULL NA NA NA
This will indicate that 285.62 is the sum of the first and 2nd values, sorted by value
DECLARE @columns varchar(max) = ''
DECLARE @allcolumns varchar(max) = ''
DECLARE @columnName varchar(1) = 'A'
DECLARE @select varchar(max) = ''
SELECT
@columns = @columns + ',''NA'' AS ' + @columnName,
@allcolumns = @allcolumns + ',' + @columnName,
@columnName = CHAR(ASCII(@columnName)+1)
FROM
#mytemptable
SET @columnName = 'A'
SELECT
@select = @select + CHAR(13) + 'UNION SELECT ' + CONVERT(varchar(100),totals) + ' AS totals' + STUFF(@columns,2+10*(ord-1),4,'''' + @columnName + ''''), @columnName = CHAR(ASCII(@columnName)+1)
FROM
(SELECT totals, ROW_NUMBER() OVER(ORDER BY totals) ord from #mytemptable)
A
SET @select = STUFF(@select,1,6,'')
SET @allcolumns = STUFF(@allcolumns, 1,1,'')
--PRINT (@select)
EXEC ( 'SELECT * FROM (
SELECT SUM(totals) AS Total, ' + @allcolumns + '
FROM (' + @select + ') A GROUP BY ' + @allcolumns + ' WITH CUBE
) sub WHERE Total = 285.62 ')
Upvotes: 2