create table #sample (
product varchar(100),
Price float
)
insert into #sample values ('Pen',10)
insert into #sample values ('DVD',29)
insert into #sample values ('Pendrive',45)
insert into #sample values ('Mouse',12.5)
insert into #sample values ('TV',49)
select * from #sample
Consider this situation ...
I have 1000$, I want to buy something listed above.
I want to spend the entire amount
So I need a query which gives how much units in all products will cost 1000$
Any help ?
It's possible to remove a lot of data by limiting the space for the current item to the money not already spent.
On my home system it takes between 2600 ms and 2800 ms to run.
On SQLFiddle the first few runs can take more, then it stabilize around 1800ms.
What's changed
#Counter
is now a temp table, it's calculated only onceCTE
s are gone, substituted by the sample table pivotedCROSS JOIN
in the Products CTE are gone, they remain in the main select but four lessCROSS JOIN
is always goodTOP
is gone, theWHERE
contition takes care of showing only the perfect solutionsLEFT JOIN
... nope they are stillCROSS JOIN
, theLEFT JOIN
are used because theCROSS JOIN
don't have theON
clause used to limit the number of rowsHow it works
The products price unpivoted make it possible to get the products price by 'name' (column name).
The
FROM
block works like 4 indentedFOR
, where the (1000 - already spent) / price clauses, limit the counters only to the values that will not exceed the 1000$.The last product is always calculated by difference (how many $ are still unspent / price), dropping a
CROSS JOIN
completelySQLFiddle Demo with 1000$ as the total money.
With the data provided there are 3531 solution
Old Answer
If you want to have you server run for all the time of you lunch here is a dumb solution.
Mind you, this solution explore all the space of the problem so the performance will be, at best, crappy.
SQLFiddle Demo with 100$ as the total money (it takes about 2 second to run)
SQLFiddle Demo with 200$ as the total money (it takes about 6 second to run)
A demo with 1000$ will probably result in a time-out
How this work
That just to say that yes you can devise a solution in SQLServer, it's not even that difficult, but that doesn't mean that you should to it.
The problem you are referring to is also known as the knapsack problem. There's a range of algorithms you can use to solve this. The most well known is dynamic programming, it requires that the weights are integer numbers, so you'd have to measure in cents. None of them are easy to implement in t-sql.
I actually found a link to someone's implementation in sql server: http://sqlinthewild.co.za/index.php/2011/02/22/and-now-for-a-completely-inappropriate-use-of-sql-server/
Notice the title, they too find it an inappropriate use of a database. I'd recommend that you solve this in a different language.
If I understand the problem statement correctly, then it's a pretty simple query:
This is hard coded and has little flexiblity. Took my system 2 minutes to run. But might be helpful, sorry if it isn't. fnGenerate_Numbers is a table function that returns integers within the range of the parameters. Ways to do that.