MySQL вопрос проблема.Сумма ТОП 3 по типу и топ 1 по группе по ссылке - PullRequest
0 голосов
/ 12 июня 2019

Я пытался написать SQL-запрос, чтобы выбрать 3 лучших типа для каждого пользователя и суммировать их с 1 лучшим типом для каждого пользователя. Я извиняюсь, если это звучит сложно, но я не могу придумать лучшего способа описать это. Запрос должен быть совместим с MySQL 5.x.

Я пытался адаптировать предыдущий запрос без радости. В настоящее время он настроен так, чтобы возвращать первые 5 строк для каждого пользователя и обрабатывать каждую вторую строку как значение 1. Я попытался изменить некоторые пункты, чтобы получить желаемый эффект без радости.

SELECT
 wsf_ref
,sum(wsf_value) as total
from (select
*,
( select count(*)
 from individual u
 where
   t.wsf_ref = u.wsf_ref and
   t.type = u.type and
   t.wsf_value <= u.wsf_value
) as number
from individual t) t
where (number <= 3 and type <> 'blue' and status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3'))
or (number = 1 and type = 'blue' and status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3'))
group by wsf_ref
order by total desc  

Пример данных

id     wsf_ref   status     type       wsf_progress   wsf_value
1      001       Approved       orange     Day 1          5
2      001       Approved       orange     Day 1          10  *
3      001       Approved       orange     Day 1          20  *
4      001       Approved       orange     Day 1          10  *
5      001       Approved       blue       Day 1          10 
6      001       Approved       blue       Day 1          25  * 
7      002       Approved       red        Day 1          10
8      002       Approved       red        Day 1          20  *
9      002       Approved       red        Day 1          30  *
10     002       Approved       red        Day 1          20  *
11     002       Approved       orange     Day 1          10
12     002       Approved       orange     Day 1          20  *
13     002       Approved       orange     Day 1          15  *
14     002       Approved       orange     Day 1          40  *
15     002       Approved       blue       Day 1          20
16     002       Approved       blue       Day 1          35
17     002       Approved       blue       Day 1          50  *

* denotes rows to be summed in the example.

Для этого примера тип «синий» - это ТОП 1. «Статус» и «прогресс» не очень актуальны в этом примере, но я бы хотел, чтобы они были включены в качестве критериев ГДЕ.

Expected Results
----------------------
wsf_ref     total
002         195
001         65

Current Results
----------------------
wsf_ref     total
002         120
001         45

Похоже, он только выбирает верхнюю 1 для каждого типа и игнорирует предложение number <= 3. </p>

1 Ответ

1 голос
/ 13 июня 2019

SQL DEMO

Сначала с пользовательскими переменными вам нужно создать rn, чтобы получить топ-3 для каждого type и ref

SELECT t.*, @rn := if(  @ref = `wsf_ref`,
                       if ( @type = `type`, 
                             @rn + 1,
                             if( @type := `type`, 1, 1)                     
                           ),
                       if ( (@ref := `wsf_ref`) or (@type := `type`), 1, 1)
                    ) as rn,
            @type,
            @ref
FROM t
CROSS JOIN ( SELECT @rn := 0, @type := '', @ref := '') as var
ORDER BY `wsf_ref`, `type`, `wsf_value` DESC ;

Частичный результат

| id | wsf_ref |   status |   type | wsf_progress | wsf_value | rn |  @type | @ref |
|----|---------|----------|--------|--------------|-----------|----|--------|------|
|  6 |       1 | Approved |   blue |        Day 1 |        25 |  1 |   blue |    1 |
|  5 |       1 | Approved |   blue |        Day 1 |        10 |  2 |   blue |    1 |
|  3 |       1 | Approved | orange |        Day 1 |        20 |  1 | orange |    1 |
|  2 |       1 | Approved | orange |        Day 1 |        10 |  2 | orange |    1 |
|  4 |       1 | Approved | orange |        Day 1 |        10 |  3 | orange |    1 |
|  1 |       1 | Approved | orange |        Day 1 |         5 |  4 | orange |    1 |
| 17 |       2 | Approved |   blue |        Day 1 |        50 |  1 |   blue |    2 |
| 16 |       2 | Approved |   blue |        Day 1 |        35 |  2 |   blue |    2 |
| 15 |       2 | Approved |   blue |        Day 1 |        20 |  3 |   blue |    2 |
| 14 |       2 | Approved | orange |        Day 1 |        40 |  1 | orange |    2 |
| 12 |       2 | Approved | orange |        Day 1 |        20 |  2 | orange |    2 |
| 13 |       2 | Approved | orange |        Day 1 |        15 |  3 | orange |    2 |
| 11 |       2 | Approved | orange |        Day 1 |        10 |  4 | orange |    2 |
|  9 |       2 | Approved |    red |        Day 1 |        30 |  1 |    red |    2 |
| 10 |       2 | Approved |    red |        Day 1 |        20 |  2 |    red |    2 |
|  8 |       2 | Approved |    red |        Day 1 |        20 |  3 |    red |    2 |
|  7 |       2 | Approved |    red |        Day 1 |        10 |  4 |    red |    2 |

Тогда используйте условное SUM

SELECT wsf_ref, SUM( CASE WHEN type = 'blue' and rn = 1 
                          THEN `wsf_value`
                          WHEN type <> 'blue' and rn in (1,2,3)
                          THEN `wsf_value`
                          ELSE 0
                     END
                   ) as sum_total
FROM ( 
        SELECT t.*, @rn := if(  @ref = `wsf_ref`,
                               if ( @type = `type`, 
                                     @rn + 1,
                                     if( @type := `type`, 1, 1)                     
                                   ),
                               if ( (@ref := `wsf_ref`) and (@type := `type`), 1, 1)
                            ) as rn,
                    @type,
                    @ref
        FROM t
        CROSS JOIN ( SELECT @rn := 0, @type := '', @ref := '') as var
        ORDER BY `wsf_ref`, `type`, `wsf_value` DESC   
     ) t
GROUP BY `wsf_ref

ВЫХОД

| wsf_ref | sum_total |
|---------|-----------|
|       1 |        65 |
|       2 |       195 |

EDIT:

После расспросов у меня появилась более простая версия:

Какое логическое значение возвращает целое число или строку переменной

DEMO

SELECT t.*,
       (@rn := if(@tr = CONCAT_WS(':', wsf_ref, type),
                  @rn + 1,
                  if(@tr := CONCAT_WS(':', wsf_ref, type), 1, 1
                    )                     
                 )
       ) as rn
FROM (SELECT t.*
      FROM t 
      ORDER BY `wsf_ref`, `type`, `wsf_value` DESC
     ) t CROSS JOIN
     (SELECT @rn := 0, @tr := '') params;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...