[英]SQL select some rows in a table so that they sum up to certain value
如何在下表中僅選擇一些行,以便它們總和到某個值?
Table
-----
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 18
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
比方說,我想要的最高價值是57 ......
所以我需要選擇上一個表中的行,使每行的qty1 + qty2 + qty3 + qty4,直到該57值,並丟棄其他行。 在這個例子中,我會得到以下內容:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 18
因為10 + 20 + 1.5 + 7.5 + 18 = 57,所以我丟棄第3和第4行......
現在我希望最高值為50,那么我應該得到:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 11
由於這些值總和為50,而第7行從第2行開始,qty4被省略......(順便說一句,行以這種特殊的方式排序,因為這是我希望考慮qtys總和的順序......它是例如,無法總結第一行1,然后是3,然后是2,然后是4 ......它們應該始終按順序1,2,3,4 ...
如果我想補充這個怎么辦? 我的意思是,在最后一個結果中沒有得到的另外兩行。
第一種情況:
id | qty1 | qty2 | qty3 | qty4
------------------------------
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
第二種情況:
id | qty1 | qty2 | qty3 | qty4
------------------------------
2 | 0.0 | 0.0 | 0.0 | 7
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
(如果第二種情況太復雜,那么如何獲得:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
因為將第2行的原始qtys相加會超過50的值,所以我將其丟棄......在這種情況下的補碼應該是:
id | qty1 | qty2 | qty3 | qty4
------------------------------
2 | 1.5 | 0.0 | 7.5 | 18
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
)
括號中的簡化選項也不錯:
SELECT foo1.*
FROM foo AS foo1
JOIN foo AS foo2
ON foo2.id <= foo1.id
GROUP
BY foo1.id
HAVING SUM(foo2.qty1 + foo2.qty2 + foo2.qty3 + foo2.qty4) <= 57
;
(你沒有提到桌子的名字,所以我和foo
一起去了。)
補充將是:
SELECT *
FROM foo
WHERE id NOT IN
( SELECT foo1.id
FROM foo AS foo1
JOIN foo AS foo2
ON foo2.id <= foo1.id
GROUP
BY foo1.id
HAVING SUM(foo2.qty1 + foo2.qty2 + foo2.qty3 + foo2.qty4) <= 57
)
;
不明白的選項更加棘手; 它是可行的,但你使用存儲過程會好得多。
讓我們這樣說:如果SQL是一種宗教信仰,那么我就會提供這種解決方案。 SQL並不是要解決這類問題,所以任何解決方案都會很糟糕。 我也不例外:)
set @limitValue := 50;
select id, newQty1, newQty2, newQty3, newQty4 from (
select id,
if(@limitValue - qty1 > 0, qty1, greatest(@limitValue, 0)) newQty1,
@limitValue := @limitValue - qty1 Total1,
if(@limitValue - qty2 > 0, qty2, greatest(@limitValue, 0)) newQty2,
@limitValue := @limitValue - qty2 Total2,
if(@limitValue - qty3 > 0, qty3, greatest(@limitValue, 0)) newQty3,
@limitValue := @limitValue - qty3 Total3,
if(@limitValue - qty4 > 0, qty4, greatest(@limitValue, 0)) newQty4,
@limitValue := @limitValue - qty4 Total4
from (
select id, qty1, qty2, qty3, qty4,
@rowTotal < @limitValue Useful,
@previousRowTotal := @rowTotal PreviousRowTotal,
@rowTotal := @rowTotal + qty1 + qty2 + qty3 + qty4 AllRowsTotal,
@rowTotal - @previousRowTotal CurrentRowTotal
from t,
(select @rowTotal := 0, @previousRowTotal := 0) S1
) MarkedUseful
where useful = 1
) Final
對於提供的數據,結果如下:
+----+---------+---------+---------+---------+
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 |
+----+---------+---------+---------+---------+
| 1 | 0 | 0 | 10 | 20 |
| 2 | 1.5 | 0 | 7.5 | 11 |
+----+---------+---------+---------+---------+
補充:
set @limitValue := 50;
select t1.id,
coalesce(t1.qty1 - newQty1, t1.qty1) newQty1,
coalesce(t1.qty2 - newQty2, t1.qty2) newQty2,
coalesce(t1.qty3 - newQty3, t1.qty3) newQty3,
coalesce(t1.qty4 - newQty4, t1.qty4) newQty4
from t t1 left join (
select id,
if(@limitValue - qty1 > 0, qty1, greatest(@limitValue, 0)) newQty1,
@limitValue := @limitValue - qty1 Total1,
if(@limitValue - qty2 > 0, qty2, greatest(@limitValue, 0)) newQty2,
@limitValue := @limitValue - qty2 Total2,
if(@limitValue - qty3 > 0, qty3, greatest(@limitValue, 0)) newQty3,
@limitValue := @limitValue - qty3 Total3,
if(@limitValue - qty4 > 0, qty4, greatest(@limitValue, 0)) newQty4,
@limitValue := @limitValue - qty4 Total4
from (
select id, qty1, qty2, qty3, qty4,
@rowTotal < @limitValue Useful,
@previousRowTotal := @rowTotal PreviousRowTotal,
@rowTotal := @rowTotal + qty1 + qty2 + qty3 + qty4 AllRowsTotal,
@rowTotal - @previousRowTotal CurrentRowTotal
from t,
(select @rowTotal := 0, @previousRowTotal := 0) S1
) MarkedUseful
where useful = 1
) Final
on t1.id = final.id
where Total1 < 0 or Total2 < 0 or Total3 < 0 or Total4 < 0 or final.id is null
對於提供的數據,結果如下:
+----+---------+---------+---------+---------+
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 |
+----+---------+---------+---------+---------+
| 2 | 0 | 0 | 0 | 7 |
| 3 | 1 | 2 | 7.5 | 18 |
| 4 | 0 | 0.5 | 5 | 13 |
+----+---------+---------+---------+---------+
請享用!
讓我們從問題中加載您的樣本數據
mysql> drop database if exists javier;
Query OK, 1 row affected (0.02 sec)
mysql> create database javier;
Query OK, 1 row affected (0.01 sec)
mysql> use javier
Database changed
mysql> create table mytable
-> (
-> id int not null auto_increment,
-> qty1 float,qty2 float,qty3 float,qty4 float,
-> primary key (id)
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> insert into mytable (qty1,qty2,qty3,qty4) values
-> ( 0.0 , 0.0 , 10 , 20 ),( 1.5 , 0.0 , 7.5 , 18 ),
-> ( 1.0 , 2.0 , 7.5 , 18 ),( 0.0 , 0.5 , 5 , 13 );
Query OK, 4 rows affected (0.05 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from mytable;
+----+------+------+------+------+
| id | qty1 | qty2 | qty3 | qty4 |
+----+------+------+------+------+
| 1 | 0 | 0 | 10 | 20 |
| 2 | 1.5 | 0 | 7.5 | 18 |
| 3 | 1 | 2 | 7.5 | 18 |
| 4 | 0 | 0.5 | 5 | 13 |
+----+------+------+------+------+
4 rows in set (0.00 sec)
mysql>
select BBBB.* from (select id,sums FROM (select A.id,A.sums from
(select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
where BB.id<=AA.id) sums from mytable AA order by id) A
INNER JOIN (SELECT 50 mylimit) B ON A.sums <= B.mylimit) AAA
UNION
(select A.id,A.sums from (select id,(select sum(qty1+qty2+qty3+qty4)
from mytable BB where BB.id<=AA.id) sums from mytable AA order by id) A
where A.sums=(select min(A.sums) sums from (select id,
(select sum(qty1+qty2+qty3+qty4) from mytable BB where BB.id<=AA.id) sums
from mytable AA order by id) A INNER JOIN (SELECT 50 mylimit) B
ON A.sums >= B.mylimit))) AAAA JOIN mytable BBBB USING (id);
select BBBB.* from mytable BBBB LEFT JOIN
(select id,sums FROM (select A.id,A.sums from (
select id,(select sum(qty1+qty2+qty3+qty4)
from mytable BB where BB.id<=AA.id) sums
from mytable AA order by id) A INNER JOIN
(SELECT 50 mylimit) B ON A.sums <= B.mylimit) AAA
UNION
(select A.id,A.sums from (select id,
(select sum(qty1+qty2+qty3+qty4) from mytable BB
where BB.id<=AA.id) sums from mytable AA order by id) A
where A.sums=(select min(A.sums) sums from (
select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
where BB.id<=AA.id) sums from mytable AA order by id) A
INNER JOIN (SELECT 50 mylimit) B ON A.sums >= B.mylimit))) AAAA
USING (id) WHERE AAAA.id IS NULL;
這是57的輸出
mysql> select BBBB.* from (select id,sums FROM (select A.id,A.sums from
-> (select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> INNER JOIN (SELECT 57 mylimit) B ON A.sums <= B.mylimit) AAA
-> UNION
-> (select A.id,A.sums from (select id,(select sum(qty1+qty2+qty3+qty4)
-> from mytable BB where BB.id<=AA.id) sums from mytable AA order by id) A
-> where A.sums=(select min(A.sums) sums from (select id,
-> (select sum(qty1+qty2+qty3+qty4) from mytable BB where BB.id<=AA.id) sums
-> from mytable AA order by id) A INNER JOIN (SELECT 57 mylimit) B
-> ON A.sums >= B.mylimit))) AAAA JOIN mytable BBBB USING (id);
+----+------+------+------+------+
| id | qty1 | qty2 | qty3 | qty4 |
+----+------+------+------+------+
| 1 | 0 | 0 | 10 | 20 |
| 2 | 1.5 | 0 | 7.5 | 18 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
mysql> select BBBB.* from mytable BBBB LEFT JOIN
-> (select id,sums FROM (select A.id,A.sums from (
-> select id,(select sum(qty1+qty2+qty3+qty4)
-> from mytable BB where BB.id<=AA.id) sums
-> from mytable AA order by id) A INNER JOIN
-> (SELECT 57 mylimit) B ON A.sums <= B.mylimit) AAA
-> UNION
-> (select A.id,A.sums from (select id,
-> (select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> where A.sums=(select min(A.sums) sums from (
-> select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> INNER JOIN (SELECT 57 mylimit) B ON A.sums >= B.mylimit))) AAAA
-> USING (id) WHERE AAAA.id IS NULL;
+----+------+------+------+------+
| id | qty1 | qty2 | qty3 | qty4 |
+----+------+------+------+------+
| 3 | 1 | 2 | 7.5 | 18 |
| 4 | 0 | 0.5 | 5 | 13 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
mysql>
這是50的輸出
mysql> select BBBB.* from (select id,sums FROM (select A.id,A.sums from
-> (select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> INNER JOIN (SELECT 50 mylimit) B ON A.sums <= B.mylimit) AAA
-> UNION
-> (select A.id,A.sums from (select id,(select sum(qty1+qty2+qty3+qty4)
-> from mytable BB where BB.id<=AA.id) sums from mytable AA order by id) A
-> where A.sums=(select min(A.sums) sums from (select id,
-> (select sum(qty1+qty2+qty3+qty4) from mytable BB where BB.id<=AA.id) sums
-> from mytable AA order by id) A INNER JOIN (SELECT 50 mylimit) B
-> ON A.sums >= B.mylimit))) AAAA JOIN mytable BBBB USING (id);
+----+------+------+------+------+
| id | qty1 | qty2 | qty3 | qty4 |
+----+------+------+------+------+
| 1 | 0 | 0 | 10 | 20 |
| 2 | 1.5 | 0 | 7.5 | 18 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
mysql> select BBBB.* from mytable BBBB LEFT JOIN
-> (select id,sums FROM (select A.id,A.sums from (
-> select id,(select sum(qty1+qty2+qty3+qty4)
-> from mytable BB where BB.id<=AA.id) sums
-> from mytable AA order by id) A INNER JOIN
-> (SELECT 50 mylimit) B ON A.sums <= B.mylimit) AAA
-> UNION
-> (select A.id,A.sums from (select id,
-> (select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> where A.sums=(select min(A.sums) sums from (
-> select id,(select sum(qty1+qty2+qty3+qty4) from mytable BB
-> where BB.id<=AA.id) sums from mytable AA order by id) A
-> INNER JOIN (SELECT 50 mylimit) B ON A.sums >= B.mylimit))) AAAA
-> USING (id) WHERE AAAA.id IS NULL;
+----+------+------+------+------+
| id | qty1 | qty2 | qty3 | qty4 |
+----+------+------+------+------+
| 3 | 1 | 2 | 7.5 | 18 |
| 4 | 0 | 0.5 | 5 | 13 |
+----+------+------+------+------+
2 rows in set (0.01 sec)
mysql>
請記住在(SELECT 50 mylimit)
子查詢中設置兩次(SELECT 50 mylimit)
。
請告訴我有這個......
您應該僅調整init
子查詢中的@limit變量初始化。 第一個查詢輸出數據到限制,secnd查詢輸出其補碼。
SELECT
id,
@qty1 as qty1,
@qty2 as qty2,
@qty3 as qty3,
@qty4 as qty4
FROM quantities q,
(SELECT @qty1:=0.0, @qty2:=0.0,
@qty3:=0.0, @qty4:=0.0,
@limit:=50.0) init
WHERE
IF(@limit > 0,
GREATEST(1,
IF(@limit-qty1 >=0,
@limit:=(@limit-(@qty1:=qty1)),
@qty1:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty2 >=0,
@limit:=(@limit-(@qty2:=qty2)),
@qty2:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty3 >=0,
@limit:=(@limit-(@qty3:=qty3)),
@qty3:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty4 >=0,
@limit:=(@limit-(@qty4:=qty4)),
@qty4:=@limit + LEAST(@limit, @limit:=0))),0)
;
補充:
SELECT
id,
IF(qty1=@qty1, qty1, qty1-@qty1) as qty1,
IF(qty2=@qty2, qty2, qty2-@qty2) as qty2,
IF(qty3=@qty3, qty3, qty3-@qty3) as qty3,
IF(qty4=@qty4, qty4, qty4-@qty4) as qty4
FROM quantities q,
(SELECT @qty1:=0.0, @qty2:=0.0,
@qty3:=0.0, @qty4:=0.0,
@limit:=50.0) init
WHERE
IF(
LEAST(
IF(@limit-qty1 >=0,
@limit:=(@limit-(@qty1:=qty1)),
@qty1:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty2 >=0,
@limit:=(@limit-(@qty2:=qty2)),
@qty2:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty3 >=0,
@limit:=(@limit-(@qty3:=qty3)),
@qty3:=@limit + LEAST(@limit, @limit:=0)),
IF(@limit-qty4 >=0,
@limit:=(@limit-(@qty4:=qty4)),
@qty4:=@limit + LEAST(@limit, @limit:=0)),
@limit), 0, 1)
;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.