MySQL CASE “Else Case When” выполняется, когда предварительное условие истинно - чего мне не хватает?
Вопрос
У меня есть таблица, которая из-за используемой нами сторонней системы иногда содержит дублирующиеся данные.Поскольку модель использует метод 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
Кроме того, вы, похоже, возвращаете одно и то же поле "данные" в обоих случаях