MySQL - Как сложить несколько диапазонов из одного столбца - PullRequest
0 голосов
/ 03 мая 2020

Я работал над этим, время от времени, в течение нескольких дней. Я должен прочитать таблицу MySQL (описанную ниже), чтобы определить, какие группы находятся в таблице. Значения столбца кода могут go от 01 до 99, и эти значения разделены на четыре группы кодов. В настоящее время я получаю кодовые группы следующим образом:

SELECT SUM(code) AS code0 FROM codes WHERE code BETWEEN 1 AND 69 ;
SELECT SUM(code) AS code1 FROM codes WHERE code BETWEEN 70 AND 79 ;
SELECT SUM(code) AS code2 FROM codes WHERE code BETWEEN 80 AND 89 ;
SELECT SUM(code) AS code3 FROM codes WHERE code BETWEEN 90 AND 99 ;

, но мне бы очень хотелось сделать это за один запрос. Я пробовал CASE / WHEN / END, но я просто не могу понять это правильно. Я перепробовал много версий, но эта подходит ближе всего:

(не работает, но закрывается)

SELECT SUM(CASE code WHEN code BETWEEN 1 AND 69 THEN code ELSE 0 END) AS code0,
    SUM(CASE code WHEN code BETWEEN 70 AND 79 THEN code ELSE 0 END) AS code1,
    SUM(CASE code WHEN code BETWEEN 80 AND 89 THEN code ELSE 0 END) AS code2,
    SUM(CASE code WHEN code BETWEEN 90 AND 99 THEN code ELSE 0 END) AS code3
  FROM codes;

возвращает:

+-------+-------+-------+-------+
| code0 | code1 | code2 | code3 |
+-------+-------+-------+-------+
|     1 |     0 |     0 |     0 |
+-------+-------+-------+-------+

(Это только считая запись '01' ???)

Но работают мои четыре отдельных запроса, которые возвращают:

SELECT SUM(code) AS code0 FROM codes WHERE code BETWEEN 1 AND 69 ;
+-------+
| code0 |
+-------+
|    55 |
+-------+
1 row in set (0.000 sec)

SELECT SUM(code) AS code1 FROM codes WHERE code BETWEEN 70 AND 79 ;
+-------+
| code1 |
+-------+
|   213 |
+-------+
1 row in set (0.000 sec)

SELECT SUM(code) AS code2 FROM codes WHERE code BETWEEN 80 AND 89 ;
+-------+
| code2 |
+-------+
|   326 |
+-------+
1 row in set (0.000 sec)

SELECT SUM(code) AS code3 FROM codes WHERE code BETWEEN 90 AND 99 ;
+-------+
| code3 |
+-------+
|  NULL |
+-------+

СОСТАВ ДАННЫХ -

codes table schema:
+-------------+-------------------------------+------+-----+---------+-------+
| Field       | Type                          | Null | Key | Default | Extra |
+-------------+-------------------------------+------+-----+---------+-------+
| code        | smallint(2) unsigned zerofill | NO   |     | 00      |       |
| descrip     | varchar(30)                   | NO   |     |         |       |
+-------------+-------------------------------+------+-----+---------+-------+

данные таблицы:

select * from codes;
+------+---------+
| code | descrip |
+------+---------+
|   01 | RWF     |
|   02 | BLK     |
|   03 | BWF     |
|   04 | CHAR    |
|   05 | RED     |
|   06 | XBRED   |
|   07 | MIXED   |
|   08 | HOLST   |
|   09 | JERSEY  |
|   10 | LGHRN   |
|   70 | WHT     |
|   71 | BLK     |
|   72 | SPOTTED |
|   80 | WHT     |
|   81 | BLK     |
|   82 | BLKFC   |
|   83 | WHTFC   |
+------+---------+

Ответы [ 3 ]

0 голосов
/ 03 мая 2020

У вас не совсем правильный синтаксис CASE , вы смешиваете две формы и заканчиваете сравнением code с логическим значением, поэтому оно суммирует только значения для code = 1. Это правильная форма:

SELECT SUM(CASE WHEN code BETWEEN  1 AND 69 THEN code ELSE 0 END) AS code0,
       SUM(CASE WHEN code BETWEEN 70 AND 79 THEN code ELSE 0 END) AS code1,
       SUM(CASE WHEN code BETWEEN 80 AND 89 THEN code ELSE 0 END) AS code2,
       SUM(CASE WHEN code BETWEEN 90 AND 99 THEN code ELSE 0 END) AS code3
FROM codes;

Вывод:

code0   code1   code2   code3
55      213     326     0

Исходя из ваших комментариев об использовании значения, следующие запросы с использованием COUNT или EXISTS будут более эффективный:

SELECT COUNT(CASE WHEN code BETWEEN 1 AND 69 THEN code END) AS code0,
       COUNT(CASE WHEN code BETWEEN 70 AND 79 THEN code END) AS code1,
       COUNT(CASE WHEN code BETWEEN 80 AND 89 THEN code END) AS code2,
       COUNT(CASE WHEN code BETWEEN 90 AND 99 THEN code END) AS code3
FROM codes

SELECT EXISTS (SELECT * FROM codes WHERE code BETWEEN 1 AND 69) AS code0,
       EXISTS (SELECT * FROM codes WHERE code BETWEEN 70 AND 79) AS code1,
       EXISTS (SELECT * FROM codes WHERE code BETWEEN 80 AND 89) AS code2,
       EXISTS (SELECT * FROM codes WHERE code BETWEEN 90 AND 99) AS code3

Демонстрация на dbfiddle

0 голосов
/ 03 мая 2020

У вас неверный синтаксис для оператора CASE, даже если ваш подход был хорошим. Исправленная версия:

SELECT SUM(CASE WHEN code BETWEEN 1 AND 69 THEN code ELSE 0 END) AS code0,
    SUM(CASE WHEN code BETWEEN 70 AND 79 THEN code ELSE 0 END) AS code1,
    SUM(CASE WHEN code BETWEEN 80 AND 89 THEN code ELSE 0 END) AS code2,
    SUM(CASE WHEN code BETWEEN 90 AND 99 THEN code ELSE 0 END) AS code3
  FROM codes;

Эмпирическое правило, когда у вас есть прямое сравнение, используйте

CASE expression
    WHEN test THEN result
    …
    ELSE otherResult
 END

При работе с диапазонами используйте

CASE
    WHEN booleanExpression THEN result
    …
    ELSE otherResult
 END
0 голосов
/ 03 мая 2020

должно работать.

SELECT 
  *
FROM
  (SELECT SUM(code) AS code0 FROM codes WHERE code BETWEEN 1 AND 69) t1,
  (SELECT SUM(code) AS code1 FROM codes WHERE code BETWEEN 70 AND 79) t2,
  (SELECT SUM(code) AS code2 FROM codes WHERE code BETWEEN 80 AND 89) t3,
  (SELECT SUM(code) AS code3 FROM codes WHERE code BETWEEN 90 AND 99) t4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...