2012-03-01 5 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 

まで取得し、だから私は、このような各行のqty1 + qty2 + qty3 + qty4その前のテーブルから行を選択する必要が

...私が欲しいのトップ値が57である、のは、言ってみましょうその57の値を削除し、他の行を破棄します。今、私が望むのトップという= 57ので、10 + 20 + 1.5 + 7.5 + 18

id | qty1 | qty2 | qty3 | qty4 
------------------------------ 
1 | 0.0 | 0.0 | 10 | 20 
2 | 1.5 | 0.0 | 7.5 | 18 

ので、私は、行3 & 4を捨てる...

:この例では、私は次のようになるだろう値が50で、その後、私が取得する必要がありますROW2からこれらの値は50にまとめるので

id | qty1 | qty2 | qty3 | qty4 
------------------------------ 
1 | 0.0 | 0.0 | 10 | 20 
2 | 1.5 | 0.0 | 7.5 | 11 

、および7、qty4はそれだから (BTWの行は、この特定の方法で順序付けられ...取り残されますqtysの合計を計算したい順番...最初のrを集計するのは有効ではありませんow1、次に3、次に2、次に4 ...などがあります。それらは常に1,2,3,4 ...の順番で合計されるべきです)

私はこれを補完することを望みますか?私は、最後の結果では得られなかった他の2つの行を意味します。

最初のケース:

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 

(第2のケースはどのように入手する方法について、あまりにも複雑である場合:

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

私は複雑なクエリの多くを書いた、と私は挑戦して好きですが、これはちょうどあなたが手続き型のコードを記述するために頼むそれらのまれなケースの一つでありますあなたの選択した言語で –

+0

簡略化された第2の場合でも?ポストの終わりにカッコ内の最後のもの...? –

+1

簡略化された第2のケースはクエリとして実行可能です。ちょうどそれを求めるためにあなたの質問を変更した場合(またはそれを求める新しい質問を作成する場合)、私は助けることができます。 –

答えて

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行... –

+0

今それは動作します!私は最後に何が間違っていたのかわからない:)それをテストして、それを私の実際のケースに適用して、私はあなたに賞金についての回答を与える;) –

+0

確かに、あなたの時間を取る:) –

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> 

完全には完全にはここで

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; 

ワークス

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

FINAL QUERY補完ワークスFINAL QUERYからサンプル・データをロードしてみましょうここでは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> 

の出力はそれぞれ2回(SELECT 50 mylimit)サブクエリでmylimitの番号を設定することを忘れないでくださいです。

あなたはinitサブクエリ内だけ@limit変数の初期化を調整する必要があります...私はこの1つを得た

+0

ありがとう:)しかし、これはちょうど私が提案した複雑なものではない単純なケースを解決します;) –

+0

@ Javier複雑なものは何ですか?あなたが50のような他の数字を使うことを意味するならば、両方のクエリ(FINALとFINAL COMPLEMENT)で '(SELECT 57 mylimit)'を '(SELECT 50 mylimit)'に置き換えてください。それ以外の場合は、複雑なケースについて説明してください。 – RolandoMySQLDBA

+0

私が与えたサンプルデータを使って、例で説明しようとします。 mylimit = 50の場合、クエリの結果はid = 2:qty1 = 1.5、qty2 = 0.0、qty3 = 7.5、qty4 = 11となるはずです。しかし、あなたのクエリは私にid = 2の行を与えません。見て分かるように、qty4 = 11はテーブルのデータにはありませんが、mylimitの値に達するまで各行にqty1 + qty2 + qty3 + qty4の値を加えた結果です。つまり、row1.qty1 + row1.qty2 + row1.qty3 + row1.qty4、次に+ row2.qty1 + row2.qty2 + row2.qty3、そして元のrow2.qty4から差し引かれた+7を加算すると50に達する= 18、あなたが望む結果に見える7を与える –

4

を教えてください。最初のクエリは上限までデータを出力し、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

ありがとう!それはサンプルデータで動作します。私の実際のデータでそれをテストさせてください、私は賞金についてあなたにお答えします... –

関連する問題