MySQL CASE “Else Case When” выполняется, когда предварительное условие истинно - чего мне не хватает?

StackOverflow https://stackoverflow.com/questions/1620973

  •  06-07-2019
  •  | 
  •  

Вопрос

У меня есть таблица, которая из-за используемой нами сторонней системы иногда содержит дублирующиеся данные.Поскольку модель использует метод EAV, нет способа отфильтровать это "правильным" способом, поэтому я объединяю данные в представление - я знаю, что это проблема со сбором данных, но мне проще исправить это на стороне отображения, чем проходить через эту систему и потенциально нарушать существующие данные и формы.Мне нужно проверить одно из двух полей, чтобы увидеть, введено ли одно или оба, но выберите только одно (в противном случае имя отображается дважды следующим образом:"Джон, Джон" вместо просто "Джон").Вот мой код для соответствующей части:

group_concat(
(
  case when (`s`.`fieldid` = 2) then `s`.`data` 
  else
    case when (`s`.`fieldid` = 35) then `s`.`data` 
    else NULL end 
  end
) separator ','),_utf8'') as first_name

Если введены оба fieldid 2 и fieldid 35, я бы ожидал, что это просто вернет значение из fieldid = 2, а не значение из fieldid = 35, поскольку предложение Else не должно выполняться, когда исходный регистр when имеет значение true.Однако он захватывает это, а затем все еще выполняет case when внутри предложения else?

Как я могу исправить этот код, чтобы он выдавал мне либо fieldid = 2, либо fieldid = 35, но не объединял их оба вместе, что приводит к дублированию имени?

Редактировать

Вот структура таблицы:

table: subscribers_data
subscriberid (int)   fieldid (int)   data (text)    

Он использует структуру E-A-V, поэтому пример записи может быть:

subscriberid          fieldid         data
1                     2               John
1                     3               Smith
1                     35              John
1                     36              Smith

где идентификаторы полей 2 и 35 являются пользовательскими полями "Имя" (определенными в отдельной таблице), а идентификаторы полей 3 и 36 являются "Фамилией".

Вот полное представление, которое я использую:

select `ls`.`subscriberid` AS `id`,
left(`l`.`name`,(locate(_utf8'_',`l`.`name`) - 1)) AS `user_id`,
ifnull(group_concat((
    case when (`s`.`fieldid` = 2) then `s`.`data` 
    when (`s`.`fieldid` = 35) then `s`.`data` 
    else NULL end) separator ','),_utf8'') AS `first_name`,
ifnull(group_concat((
    case when (`s`.`fieldid` = 3) then `s`.`data` 
    when (`s`.`fieldid` = 36) then `s`.`data` 
    else NULL end) separator ','),_utf8'') AS `last_name`,
ifnull(`ls`.`emailaddress`,_utf8'') AS `email_address`,
ifnull(group_concat((
    case when (`s`.`fieldid` = 81) then `s`.`data` 
    else NULL end) separator ','),_utf8'') AS `mobile_phone`,
ifnull(group_concat((
    case when (`s`.`fieldid` = 100) then `s`.`data` 
    else NULL end) separator ','),_utf8'') AS `sms_only` 
from ((`list_subscribers` `ls` 
join `lists` `l` on((`ls`.`listid` = `l`.`listid`))) 
left join `subscribers_data` `s` on((`ls`.`subscriberid` = `s`.`subscriberid`))) 
where (left(`l`.`name`,(locate(_utf8'_',`l`.`name`) - 1)) regexp _utf8'[[:digit:]]+') 
group by `ls`.`subscriberid`,`l`.`name`,`ls`.`emailaddress`

Представление используется в качестве модели для приложения Ruby on Rails, поэтому я использую креативный взлом, чтобы подделать "user_id", который ожидает Rails (мы называем поле list.name в таблице списков используется числовой идентификатор, который наше интерфейсное приложение Rails генерирует, когда мы добавляем нового пользователя, поэтому я извлекаю только это число, чтобы представление выглядело как таблица базы данных Rails-convention)

Это было полезно?

Решение

Что-нибудь внутри group_concat() у него нет способа увидеть контекст, в котором он запущен.Итак, у вас есть две строки в одной группе, одна с fieldid=2 и во-вторых, с fieldid=35, он выполнит следующее:

  • обрабатывающий ряд с fieldid=2...
    • s.fieldid = 2 верно, вернуть s.data
  • обрабатывающий ряд с fieldid=35...
    • s.fieldid = 2 является ложным, попробуйте else часть
    • s.fieldid = 35 верно, вернуть s.data

Это объясняет, почему "Джон" возвращается несколько раз.Единственный способ исправить это - запустить другой запрос вне group_concat().

Редактировать:

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

SELECT ...
   min(CASE WHEN s.fieldid IN (2,35) THEN s.data ELSE NULL END) AS first_name
...

В качестве альтернативы вы можете сделать group_concat(DISTINCT ...) если эти два значения не могут отличаться (в противном случае вы получили бы, например"Джон, Джонни").Однако почему у вас есть два значения для first_name / last_name?

Другие советы

Я не специалист по mysql, но в инструкции sql server case вы могли бы сделать это без первого "else"

case
  when fieldid = 2 then data
  when fieldid = 35 then data
  else null
end

Кроме того, вы, похоже, возвращаете одно и то же поле "данные" в обоих случаях

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top