简体   繁体   中英

SELECT, how to combine some rows as one, show rows with specific column value first and exclude a row

I have two tables, units and power . Take a look at:

The power table:

+----+-------+
| id | power |
+----+-------+
|  1 |     2 |
|  2 |     4 |
|  3 |     6 |
|  4 |     8 |
+----+-------+

The units table:

 +----+---------+----------+--------+----------+---+---+
    | id | user_id | power_id | amount | group_id | x | y |
    +----+---------+----------+--------+----------+---+---+
    |  1 |      10 |        3 |   1000 |        0 | 1 | 1 |
    |  2 |      10 |        3 |   1000 |        0 | 1 | 1 |
    |  3 |      10 |        3 |   1000 |        0 | 1 | 1 |
    |  4 |      11 |        2 |    100 |        4 | 1 | 1 |
    |  5 |      11 |        2 |    100 |        4 | 1 | 1 |
    |  6 |      11 |        1 |    100 |        4 | 1 | 1 |
    |  7 |      12 |        4 |   1000 |        0 | 1 | 1 |
    +----+---------+----------+--------+----------+---+---+

I want to get result looking like this:

+----------+--------------+-------------+----------+---------+--+
| units.id | total_amount | total_power | group_id | user_id |  |
+----------+--------------+-------------+----------+---------+--+
|        3 |         1000 |        6000 |        0 |      10 |  |
|        2 |         1000 |        6000 |        0 |      10 |  |
|        4 |          300 |        1000 |        4 |      11 |  |
|        7 |         1000 |        8000 |        0 |      12 |  |
+----------+--------------+-------------+----------+---------+--+

Explanation:

  1. Exclude a specific id, should work same for both a single row and a row which is a sum of multiple rows in the table. As you see, in the result set, row with id 1 was excluded. The id is provided by the app, I think it's better to do it in MySQL than PHP, because MySQL could just discard this row (I think), but with PHP it would have to do if() checking for every loop iteration, which seems less efficient.

  2. Show the summed-rows row before single rows, every time.

  3. Show user's units before other users', every time. You can see that when rows with user_id of 10 (imagine this user is the one seeing the page) appear first in my result set.

  4. Show units with highest power first.

  5. Show units with highest amount first.

  6. Show units with highest id first.

The last(4.5.6) are sorted in regards to the priority of the result set, with 4th having the most of it. I have this query:

SELECT   units.id,
         units.amount*power.power AS total_power,
         Sum(units.amount)        AS total_amount
FROM     units
JOIN     power
ON       units.power_id = power.id
WHERE    x = ?
AND      y = 1
GROUP BY group_id
ORDER BY group_id desc, total_power desc, total_amount desc, units.id desc limit ?,?

But it combines all units where group_id is 0, however I want units with group_id=0 to be separate rows in the result set. How to do that? Thanks!

Edit : To answer @Linoff's question about how I determine which id to exclude, I exclude the 1 in the example because a user always will see the result set through accessing it with a unit_id, which, again, in my example happens to be 1 . I hope it is clear now. Edit : The user can access this list of units on page " index.php?page=unit/view&id= . Then I SELECT the entered id separately for the purpose of my app, and then SELECT the list. But as I already have data for the entered id (for instance, 1 in this case) I do not need to have them when I SELECT from the units and power .

@Anonymous, to answer your question 1, answer 1 is: all rows with same group_id (except 0 which is a not-a-group marker) are grouped and combined together, so rows which are id 4 , 5 and 6 which have identical group_id are combined. My problem is, I don't know how to exclude grouping for rows which are stand alone (no group marking) and how to sort the result so the rows with specified user_id are sorted first and grouped rows (4,5,6-turned-to-4) are also sorted first, but in user_id=10-first,user_id=??-second hierarchy, if this makes sense.

I think this is what you want :

CREATE TABLE Power  (id int,  power int);
CREATE TABLE demo (id integer primary key, name varchar(20), hint text);
CREATE TABLE units (id, user_id, power_id, amount, group_id, x, y);

SELECT   1 as spec2_HIDETHIS,  /* Spec 2 show the groupedrows first */
         units.id    as units_ID,
         units.amount*power.power AS total_power,
         units.amount        AS total_amount,
         units.group_id      as group_id
FROM     units
JOIN     power
ON       units.power_id = power.id
WHERE    units.group_id=0  /*  */
AND      units.id != 1  /* Spec no 1 : exclud specific id */
union 
SELECT   0 as spec2_HIDETHIS,  /* Spec 2 show the groupedrows first */
         min(units.id) as units_ID ,
         units.amount*power.power AS total_power,
         Sum(units.amount)        AS total_amount,
         units.group_id           as group_id
FROM     units
JOIN     power
ON       units.power_id = power.id
where    units.group_id > 0
AND      units.id != 1  /* Spec no 1 : exclud specific id */
GROUP BY group_id
ORDER BY spec2_HIDETHIS, group_id desc, total_power desc, total_amount desc, units_ID desc  

Fiddle Link , you need to click on run to get the results.

What I do not understand is spec 2 : "show the grouped before the non grouped. " That means that units id 4 should appear first in the list which it doesn't in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM