2012-03-01 88 views
10

如何才能在下表中選擇一些行,以便它們總計爲某個值?SQL選擇表中的某些行,以便它們總計爲某個值

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,並從ROW2 7,qty4被冷落...... (BTW行以這種特別的方式訂購,因爲這是我希望說明qtys的總和的順序......總結第一個r是無效的ow1,然後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 

因爲添加了原來qtys第2行將超過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 

+1

我已經寫了很多複雜的查詢,我喜歡承擔一個挑戰,但這是那些只是乞求你寫程序代碼少見的情況用你選擇的語言。 – 2012-03-01 23:40:18

+0

即使是簡化的第二種情況?在帖子末尾括號中的最後一個......? – 2012-03-01 23:41:42

+1

簡化的第二種情況可作爲查詢使用。如果你修改你的問題來問這個問題(或者創建一個新的問題,那就要求),我可以提供幫助。 – 2012-03-01 23:54:06

回答

7

讓我們這樣說:如果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 | 
+----+---------+---------+---------+---------+ 

享受!

+0

只是嘗試了所提供的解決方案,但對於補充案例,使用相同的樣本數據,我沒有得到你顯示的結果,但只是從數據表中的原始4行... – 2012-03-06 15:49:55

+0

現在它的工作原理!我不知道我上次做錯了什麼:)讓我測試它,並將其應用於我的真實案例,我會給你一個關於賞金的答案;) – 2012-03-07 15:59:47

+0

當然,慢慢來:) – 2012-03-07 19:54:32

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 
     ) 
; 

非熟練的選項更棘手;這是可行的,但你會更好使用stored procedure

4

讓我們從問題

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> 

最終查詢,充分WORKS

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); 

最終查詢補,充分WORKS

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)子查詢mylimit各兩次。

請告訴我這一個...

+0

謝謝:)但是這只是解決了我提出的簡單情況,而不是複雜的情況;) – 2012-03-07 16:04:23

+0

@Javier什麼是複雜的?如果你的意思是使用其他一些數字,例如50,只需在兩個查詢(FINAL和FINAL COMPLEMENT)中用'(SELECT 50 mylimit)'替換'(SELECT 57 mylimit)',它們將完美工作。否則,請解釋複雜的情況。 – RolandoMySQLDBA 2012-03-07 16:09:31

+0

我會嘗試用示例來解釋我使用的樣本數據。在mylimit = 50的情況下,查詢結果應爲id = 2:qty1 = 1.5,qty2 = 0.0,qty3 = 7.5,qty4 = 11。但是,您的查詢給我沒有id = 2的行。如您所見,qty4 = 11不是數據表中的數據,而是每行添加qty1 + qty2 + qty3 + qty4的值直到達到mylimit值的結果。也就是說,當你添加50時,就會達到:row1.qty1 + row1.qty2 + row1.qty3 + row1.qty4 then + row2.qty1 + row2.qty2 + row2.qty3 then +7從原始row2.qty4中減去= 18,這給出了你在期望的結果上看到的7個 – 2012-03-07 18:58:02

4

你應該調整隻在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:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty2 >=0, 
      @limit:=(@limit-(@qty2:=qty2)), 
      @qty2:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty3 >=0, 
      @limit:=(@limit-(@qty3:=qty3)), 
      @qty3:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty4 >=0, 
      @limit:=(@limit-(@qty4:=qty4)), 
      @qty4:[email protected] + LEAST(@limit, @limit:=0))),0) 
; 

補語:

SELECT 
    id, 
    IF([email protected], qty1, [email protected]) as qty1, 
    IF([email protected], qty2, [email protected]) as qty2, 
    IF([email protected], qty3, [email protected]) as qty3, 
    IF([email protected], qty4, [email protected]) 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:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty2 >=0, 
     @limit:=(@limit-(@qty2:=qty2)), 
     @qty2:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty3 >=0, 
     @limit:=(@limit-(@qty3:=qty3)), 
     @qty3:[email protected] + LEAST(@limit, @limit:=0)), 
     IF(@limit-qty4 >=0, 
     @limit:=(@limit-(@qty4:=qty4)), 
     @qty4:[email protected] + LEAST(@limit, @limit:=0)), 
     @limit), 0, 1) 
; 
+0

謝謝!它可以處理樣本數據。讓我用我的真實數據進行測試,然後我會回答你關於賞金的事情...... – 2012-03-07 16:07:15