подсчет фамилий в диапазоне a-d, e-h, i-l …. с помощью MySQL

#mysql

#mysql

Вопрос:

У меня есть таблица фамилий, и я хочу подсчитать количество фамилий в каждом алфавитном диапазоне A-D или E-H и т.д.

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

 select count(*) FROM people 
group by surname REGEXP '^[a-d].*', 
         surname REGEXP '^[e-h].*', 
         surname REGEXP '^[i-l].*', 
         surname REGEXP '^[m-p].*', 
         surname REGEXP '^[q-t].*', 
         surname REGEXP '^[u-z].*';
  

Ответ №1:

Вот лучший способ добиться этого (в любом случае используя регулярное выражение):

 select
    sum(surname REGEXP '^[a-dA-D].*') as ad_count,
    sum(surname REGEXP '^[e-hE-H].*') as eh_count,
    sum(surname REGEXP '^[i-lI-L].*') as il_count,
    sum(surname REGEXP '^[m-pM-P].*') as mp_count,
    sum(surname REGEXP '^[q-tQ-T].*') as qd_count,
    sum(surname REGEXP '^[u-zU-Z].*') as uz_count
from people
  

Эта элегантная краткость работает из-за того, что в mysql true is 1 и false is 0 , таким образом sum(some condition) , подсчитывается, сколько раз это верно.

кстати, я добавил верхний регистр в ваше регулярное выражение.

Вы получите лучшую производительность, выбрав из внутреннего select, который выполняет работу по более эффективному вычислению группы (например, используя регистр для substr(фамилия, 1, 1)), а затем суммируя тесты с этим вычисленным значением vale.

Комментарии:

1. Это решение было бы лучше, поскольку оно не потребует от mysql использования временной таблицы и сортировки файлов, как при использовании GROUP BY will.

2. Вряд ли «лучший способ». Все эти ненужные вызовы регулярных выражений * содрогаются*

Ответ №2:

Регулярное выражение является излишним и здесь совершенно не нужно.

Возможно, что-то вроде этого, используя базовую алгебру строк:

 SELECT
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'a' AND 'd' THEN 1 ELSE 0 END) AS `SUM_a-d`,
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'e' AND 'h' THEN 1 ELSE 0 END) AS `SUM_e-h`,
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'i' AND 'l' THEN 1 ELSE 0 END) AS `SUM_i-l`,
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'm' AND 'p' THEN 1 ELSE 0 END) AS `SUM_m-p`,
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'q' AND 't' THEN 1 ELSE 0 END) AS `SUM_q-t`,
   SUM(CASE WHEN SUBSTR(`surname`, 1, 1) BETWEEN 'u' AND 'z' THEN 1 ELSE 0 END) AS `SUM_u-z`
FROM `people`
  

Комментарии:

1. Рассмотрите возможность более элегантного выражения как sum(substr(surname, 1, 1) between 'a' and 'd') etc. Меньше значит больше.

Ответ №3:

Вы можете сделать запрос немного более явным, например:

 SELECT 
  SUM(CASE WHEN  surname REGEXP '^[a-d].*' THEN 1 ELSE 0 END) AS a_d_count
  ,SUM(CASE WHEN surname REGEXP '^[e-h].*' THEN 1 ELSE 0 END) AS e_h_count
  ,SUM(CASE WHEN surname REGEXP '^[i-l].*' THEN 1 ELSE 0 END) AS i_l_count
  ,SUM(CASE WHEN surname REGEXP '^[m-p].*' THEN 1 ELSE 0 END) AS m_p_count
  ,SUM(CASE WHEN surname REGEXP '^[q-t].*' THEN 1 ELSE 0 END) AS q_t_count
  ,SUM(CASE WHEN surname REGEXP '^[u-z].*' THEN 1 ELSE 0 END) AS u_z_count
FROM (SELECT surname FROM people ORDER BY surname ASC) p
  

Ответ №4:

Избегая регулярных выражений и условных выражений, вы можете сделать это:

 SELECT CONCAT(LEFT(UPPER(surname),1), '-', CHAR(ASCII(UPPER(surname)) 3)) AS r, 
  count(id) 
FROM people
GROUP BY ROUND((ASCII(UPPER(surname)-65)/4),0);
  

Это устанавливает ваши диапазоны длиной в 4 буквы, что означает, что последний диапазон равен «yz», но вы можете изменить это с помощью немного большей математики.