可以通過將當前項目的空間限制爲尚未使用的資金來刪除大量數據。
在我的家庭系統上,運行需要2600毫秒和2800毫秒。
在SQLFiddle上,前幾次運行可能需要更多,然後穩定在1800毫秒左右。
WITH Unit(N) AS (
SELECT N
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) t(N)
), Counter(N) AS (
SELECT u.n + 10*te.n + 100*hu.n
FROM Unit u CROSS JOIN Unit te CROSS JOIN Unit hu
WHERE u.n + 10*te.n + 100*hu.n <= (SELECT 1000/Min(Price) FROM Sample))
SELECT N INTO #Counter FROM Counter;
WITH Products AS (
SELECT [Pen], [DVD], [PenDrive], [Mouse], [TV]
FROM (SELECT product, price FROM sample) s PIVOT
(MAX(price) FOR product IN ([Pen], [DVD], [PenDrive], [Mouse], [TV])) p
)
SELECT cP.N Pen, cD.N DVD, cPe.N PenDrive, cM.N Mouse
, CAST((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N - p.Mouse * cM.N)/p.TV as INT) TV
, Money = p.pen * cP.N + p.DVD * cD.N + p.PenDrive * cPe.N
+ p.Mouse * cM.N
+ p.TV * CAST((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N - p.Mouse * cM.N)/p.TV as INT)
From Products p
LEFT Join #Counter cP ON cP.N <= (1000/p.Pen)
LEFT Join #Counter cD ON cD.N <= ((1000 - p.pen * cP.N)/p.DVD)
LEFT Join #Counter cPe
ON cPe.N <= ((1000 - p.pen * cP.N - p.DVD * cD.N)/p.PenDrive)
LEFT Join #Counter cM
ON cM.N <= ((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N)/p.Mouse)
WHERE p.pen * cP.N + p.DVD * cD.N
+ p.PenDrive * cPe.N + p.Mouse * cM.N
+ p.TV * CAST((1000 - p.pen * cP.N - p.DVD * cD.N - p.PenDrive * cPe.N
- p.Mouse * cM.N)/p.TV as INT) = 1000
什麼改變
- 的
#Counter
現在是一個臨時表,它是隻計算一次
- 的各種產品
CTE
s的消失了,樣品臺取代轉動
- 產品中的
CROSS JOIN
ŝCTE都走了,他們仍然在主選擇不過四少CROSS JOIN
總是好的
- 的
TOP
消失了,WHERE
contition需要只顯示了完美的解決方案的護理
- 在主選擇我們現在有
LEFT JOIN
... 沒了他們仍然CROSS JOIN
,將LEFT JOIN
被使用,因爲CROSS JOIN
沒有使用限制的行數的ON
條款
它是如何工作的
未轉讓的產品價格可以通過'name'(列名)獲得產品價格。
FROM
塊的工作方式類似於4縮進FOR
,其中(1000 - 已用完)/ price子句將計數器限制爲僅限於不超過1000 $的值。
最後的產品總是被區別(多少$仍然未動用/價格)計算,丟棄CROSS JOIN
完全
SQLFiddle Demo 1000 $的總金額。
隨着提供的數據有3531解決方案
老回答
如果你想有你的服務器運行爲你的午餐所有的時間在這裏是一個愚蠢的解決方案。
請注意,此解決方案可以探索問題的所有空間,因此性能最好不過於糟糕。
WITH Base(N) AS(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1)
, Unit(N) AS (
SELECT Row_Number() Over (ORDER BY (SELECT NULL)) - 1
FROM Base)
, Counter(N) AS (
SELECT u.n + 10*te.n + 100*hu.n + 1000*th.n
FROM Unit u
CROSS JOIN Unit te --tens
CROSS JOIN Unit hu --hundreds
CROSS JOIN Unit th --thousands
WHERE u.n + 10*te.n + 100*hu.n + 1000*th.n <= (SELECT 1000/Min(Price)
FROM Sample))
, Pens AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Pen' AND N <= 1000/Price)
, DVDs AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'DVD' AND N <= 1000/Price)
, Pendrives AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Pendrive' AND N <= 1000/Price)
, Mouses AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Mouse' AND N <= 1000/Price)
, TVs AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'TV' AND N <= 1000/Price
)
SELECT TOP 10
Pen = p.Quantity
, DVD = d.Quantity
, Pendrive = pe.Quantity
, Mouse = m.Quantity
, TV = t.Quantity
, Price = p.Price + d.price + pe.price + m.price + t.price
FROM pens p
CROSS JOIN DVDs d
CROSS JOIN Pendrives pe
CROSS JOIN Mouses m
CROSS JOIN TVs t
WHERE p.Price + d.price + pe.price + m.price + t.price <= 1000
ORDER BY p.Price + d.price + pe.price + m.price + t.price DESC
SQLFiddle Demo $ 100爲總錢(需要約2秒至運行)
SQLFiddle Demo與$ 200爲總錢(它需要大約6秒鐘來運行)
甲演示與1000 $可能會導致超時
這項工作如何
- 基地作爲單位的基地。
- 計數單位從0到9
- 計數器使用計數單位從0到9999,或者您想要花費的較便宜的金額除以較便宜的物品的價格所徵收的限制。
- 每件物品都有自己的CTE來計算該項目在您的首都內的任何次數的價格。
- 產品CTE交叉連接,以檢查每個組合的限制內的金錢。
- TOP 10在這裏,因爲可以有多個組合使用確切的金額。
這只是說,是的,你可以在SQLServer中設計一個解決方案,但它並不那麼困難,但這並不意味着你應該這樣做。
您是否想在t-sql中實現[揹包問題](http://en.wikipedia.org/wiki/Knapsack_problem)的解決方案? – flup
不清楚您是否想知道每件產品有多少可以1000美元購買,或者您可以購買1000美元的產品的數量和組合。 – Frazz
我可以用1000美元購買多少種和哪些產品組合。應該是所有產品的混合物。 – vignesh