I'm searching for an SQL-Query that can map a set of items of an individual size to a set off buckets of individual size.
I would like to satisfy the following conditions:
- The size of a bucket has to be bigger or equal the size of an item.
- Every bucket can contain only one item or it is left empty.
- Every item can only be placed in one bucket.
- No item can be split to multiple buckets.
- I want to fill the buckets in a way, that the smallest unused buckets are filled first.
- Then initial item and bucket sets can be ordered by size or id, but are not incremental
- Sizes and ids of initial bucket and item sets can be arbitrary and do not start at a known minimum value
- The result has to be always correct, when there is a valid mapping
- The result is allowed to be incorrect if the is no valid mapping (for example if there are more items than buckets), but I would appreciate, when the result is an empty set or has another property/signal that indicates an incorrect result.
To give you an example, let's say my bucket and items tables look like that:
Bucket: Item:
+---------------------+ +---------------------+
| BucketID | Size | | ItemID | Size |
+---------------------+ +---------------------+
| 1 | 2 | | 1 | 2 |
| 2 | 2 | | 2 | 2 |
| 3 | 2 | | 3 | 5 |
| 4 | 4 | | 4 | 11 |
| 5 | 4 | | 5 | 12 |
| 6 | 7 | +---------------------+
| 7 | 9 |
| 8 | 11 |
| 9 | 11 |
| 10 | 12 |
+---------------------+
Then, I'd like to have a mapping that is returning the following result table:
Result:
+---------------------+
| BucketID | ItemID |
+---------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
| 4 | NULL |
| 5 | NULL |
| 6 | 3 |
| 7 | NULL |
| 8 | 4 |
| 9 | NULL |
| 10 | 5 |
+---------------------+
Since there is no foreign key relation or something I could fix the columns to their corresponding bucket (but only the relation Bucket.Size >= Item.Size) I'm have a lot of trouble describing the result with a valid SQL query. Whenever I use joins or sub selects, I get items in buckets, that are to big (like having an item of size 2 in a bucket of size 12, while a bucket of size 2 is still available) or I get the same item in multiple buckets.
I spent some time now to find the solution myself and I am close to say, that it is better not to declare the problem in SQL but in an application, that is just fetching the tables.
Do you think this task is possible in SQL? And if so, I would really appreciate if you can help me out with a working query.
Edit : The query should be compatible to at least Oracle, Postgres and SQLite databases
Edit II: An SQL Fiddle with the given test set above an example query, that returns a wrong result, but is close, to what the result could look like http://sqlfiddle.com/#!15/a6c30/1
I'd say that a single SQL query is maybe not the tool for the job as the buckets are "consumed" by allocating items to them. You can use SQL, but not a single query. suggestion in pseudocode below:
Using the table definition from @SoulTrain (but requiring the data to be sorted in advance):
Try this... I was able to implement this using
recursive CTE
, all in 1 single SQL statementThe only assumption I had was that the Bucket and Item data set are sorted.