2012-03-01 38 views
10

Làm cách nào tôi có thể chọn chỉ một số hàng trong bảng sau để tổng hợp giá trị nhất định?SQL chọn một số hàng trong bảng sao cho tổng hợp giá trị nhất định

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 

Hãy nói rằng, giá trị đầu tôi muốn là 57 ...

Vì vậy, tôi cần phải lựa chọn các hàng từ bảng trước đó rằng qty1 + qty2 + qty3 + qty4 của mỗi hàng, có được cho đến khi giá trị 57 đó và loại bỏ các hàng khác. Trong ví dụ này, tôi sẽ nhận được như sau:

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

Bởi vì 10 + 20 + 1,5 + 7,5 + 18 = 57, vì vậy tôi loại bỏ hàng 3 & 4 ...

Bây giờ tôi mong rằng đầu giá trị là 50, sau đó tôi sẽ nhận được:

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

vì các giá trị tổng hợp lên đến 50, và 7 từ row2, qty4 được bỏ qua ... (BTW các hàng được sắp xếp theo cách đặc biệt này bởi vì đó là thứ tự mà tôi muốn tính cho số tiền qty ... Nó không hợp lệ để tổng hợp đầu tiên r ow1, sau đó 3, sau đó 2 rồi 4, ví dụ ... Chúng phải luôn được tính theo thứ tự 1,2,3,4 ...)

Nếu tôi muốn bổ sung điều này thì sao? Ý tôi là, hai hàng còn lại tôi không có trong kết quả cuối cùng.

trường hợp đầu tiên:

id | qty1 | qty2 | qty3 | qty4 
------------------------------ 
3 | 1.0 | 2.0 | 7.5 | 18 
4 | 0.0 | 0.5 | 5 | 13 

Thứ hai trường hợp:

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 

(Nếu trường hợp thứ hai là quá phức tạp, làm thế nào về việc thu thập:

id | qty1 | qty2 | qty3 | qty4 
------------------------------ 
1 | 0.0 | 0.0 | 10 | 20 

Bởi vì thêm lên qtys gốc của hàng 2 sẽ vượt quá giá trị 50, tôi loại bỏ nó ... Bổ sung trong trường hợp này nên chỉ là:

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

Tôi đã viết rất nhiều truy vấn phức tạp, và tôi thích tham gia vào một thách thức, nhưng đây là một trong những trường hợp hiếm hoi mà chỉ đặt ra để bạn có thể viết mã thủ tục bằng ngôn ngữ bạn chọn. –

+0

ngay cả đối với trường hợp thứ hai được đơn giản hóa? những cái cuối cùng trong dấu ngoặc đơn ở cuối bài đăng ...? –

+1

Trường hợp thứ hai được đơn giản hóa có thể thực hiện được dưới dạng truy vấn. Nếu bạn sửa đổi câu hỏi của mình để yêu cầu điều đó (hoặc tạo một câu hỏi mới chỉ yêu cầu), tôi có thể giúp bạn. –

Trả lời

7

Hãy đặt nó theo cách này: Nếu SQL là một tôn giáo tôi sẽ đi đến địa ngục để cung cấp giải pháp này. SQL không có nghĩa là để giải quyết loại vấn đề này, vì vậy bất kỳ giải pháp nào cũng sẽ rất kinh khủng.Mine cũng không ngoại lệ :)

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 

Đối với các dữ liệu được cung cấp, kết quả này trong:

+----+---------+---------+---------+---------+ 
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 | 
+----+---------+---------+---------+---------+ 
| 1 | 0  |  0 | 10  |  20 | 
| 2 | 1.5  |  0 | 7.5  |  11 | 
+----+---------+---------+---------+---------+ 

Và sự bổ sung:

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 

Đối với các dữ liệu được cung cấp, kết quả này trong:

+----+---------+---------+---------+---------+ 
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 | 
+----+---------+---------+---------+---------+ 
| 2 |  0 | 0  | 0  |  7 | 
| 3 |  1 | 2  | 7.5  |  18 | 
| 4 |  0 | 0.5  | 5  |  13 | 
+----+---------+---------+---------+---------+ 

Tận hưởng!

+0

chỉ thử các giải pháp được cung cấp, nhưng đối với trường hợp bổ sung, sử dụng cùng một mẫu dữ liệu, tôi không có kết quả bạn hiển thị, nhưng chỉ là 4 hàng gốc từ bảng dữ liệu ... –

+0

bây giờ nó hoạt động! Tôi không biết tôi đã làm gì sai lần trước :) Hãy để tôi kiểm tra nó và áp dụng nó cho trường hợp thực sự của tôi và tôi sẽ cung cấp cho bạn một câu trả lời về tiền thưởng;) –

+0

Chắc chắn, hãy dành thời gian của bạn :) –

13

Các tùy chọn đơn giản hóa trong ngoặc đơn không phải là quá xấu:

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 
; 

(Bạn đã không đề cập đến tên của bảng, vì vậy tôi đã đi với foo).

Bổ sung sẽ là:

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

Tùy chọn không được minh bạch là phức tạp hơn nhiều; nó có thể thực hiện được, nhưng bạn nên sử dụng số stored procedure tốt hơn.

4

Hãy tải dữ liệu mẫu của bạn từ các câu hỏi

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> 

QUERY CUỐI CÙNG LÀ HOÀN TOÀN CÔNG TRÌNH

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

CUỐI CÙNG bổ sung cho QUERY RẰNG HOÀN TOÀN CÔNG TRÌNH

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; 

đây là đầu ra cho 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> 

Đây là kết quả cho 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> 

Hãy nhớ để thiết lập số cho mylimit trong (SELECT 50 mylimit) subquery hai lần mỗi.

Xin vui lòng cho tôi có một này ...

+0

cảm ơn :) tuy nhiên điều này chỉ giải quyết trường hợp đơn giản tôi đề xuất, không phải là một phức tạp;) –

+0

@Javier phức tạp nhất là gì? Nếu bạn muốn sử dụng một số khác như 50, chỉ cần thay thế '(SELECT 57 mylimit)' bằng '(SELECT 50 mylimit)' trong cả hai truy vấn (FINAL và FINAL COMPLEMENT) và chúng sẽ hoạt động hoàn hảo. Nếu không, hãy giải thích trường hợp phức tạp. – RolandoMySQLDBA

+0

Tôi sẽ cố gắng giải thích bằng ví dụ, sử dụng dữ liệu mẫu tôi đã cung cấp. Với mylimit = 50, kết quả của truy vấn nên cho id = 2: qty1 = 1,5, qty2 = 0,0, qty3 = 7,5, qty4 = 11. Tuy nhiên, truy vấn của bạn cho tôi không có hàng cho id = 2. Như bạn có thể thấy, qty4 = 11 không phải là những gì bảng có trong dữ liệu của nó, nhưng là kết quả của việc thêm các giá trị của qty1 + qty2 + qty3 + qty4 trên mỗi hàng cho đến khi đạt được giá trị mylimit. Tức là, 50 được đạt tới khi bạn thêm: row1.qty1 + row1.qty2 + row1.qty3 + row1.qty4 rồi + row2.qty1 + row2.qty2 + row2.qty3 rồi +7 được trừ từ hàng ban đầu2.qty4 = 18, cung cấp cho 7 bạn thấy trên kết quả mong muốn –

4

Bạn nên điều chỉnh chỉ khởi tạo biến @limit trong init subquery. Truy vấn đầu tiên xuất dữ liệu lên đến giới hạn, truy vấn thứ hai xuất ra phần bổ sung của nó.

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

Các bổ sung:

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

cảm ơn! nó hoạt động với dữ liệu mẫu. hãy để tôi kiểm tra nó với dữ liệu thực sự của tôi và tôi sẽ trả lời bạn về tiền thưởng ... –

Các vấn đề liên quan