Условный выбор в MySQL - PullRequest
       24

Условный выбор в MySQL

1 голос
/ 15 февраля 2012

Я работаю над запросом mysql, и он вызывает у меня головную боль!

Сценарий:

Я создаю веб-сайт, на котором люди могут выбирать отрасли, которые их интересуют (NOTIFY_INDUSTRY). Я присоединяю выбранные значения и сохраняю в поле базы данных.

Пример: участник выбирает сельское хозяйство (id = 9) и нефть и газ (id = 13). Я присоединяюсь к ним как 9-13 и храню в базе данных. Пользователи могут выбрать несколько отраслей, не ограничиваясь двумя.

Кроме того, участники могут выбрать отрасль (COMPANY_INDUSTRY), к которой они относятся, при условии, что информационные технологии также хранятся в базе данных.

Sample table (members):

ID
EMAIL
COMPANY_NAME
COMPANY_INDUSTRY
NOTIFY_INDUSTRY

Проблема:

Когда новый пользователь регистрируется на веб-сайте, почта (сообщения отправляются ежедневно) отправляется существующим пользователям, которые считают отрасль нового пользователя (COMPANY_INDUSTRY) одной из своих заинтересованных отраслей (NOTIFY_INDUSTRY).

Что я сделал:

$sql="select id, email
      from members
      where notify_industry in (
        select company_industry
        from members
        where datediff($today, date_activated) <= 1)"

Это не выбирает правильных членов, и я не знаю, как это сделать

EDIT - Точная проблема с токовым выходом:

Не возвращает строки, даже если это необходимо.

Предполагается, что новый пользователь company_industry равен 9, и существует пользователь с notify_industry: 10-9-20; он предназначен для возврата электронной почты существующих участников, поскольку новый участник входит в категории интересов существующего участника; но я получаю пробелы

Ответы [ 5 ]

12 голосов
/ 15 февраля 2012

Как отметил @Shiplu, это в значительной степени проблема нормализации.Несмотря на то, что некоторые люди, кажется, думают, многозначные столбцы - это убийство , чтобы попытаться понять это правильно.

Ваша основная проблема:
У вас есть участники, которые заинтересованы в одном илибольше компаний / отраслей, которые принадлежат одной или нескольким отраслям.Структура вашей таблицы, вероятно, должна начинаться с:

Industry
===============
id  -- autoincrement
name  -- varchar

Company
==============
id  -- autoincrement
name  -- varchar

Company_Industry
===============
companyId  -- fk reference to Company.id
industryId  -- fk reference to Industry.id

Member
===============
id  -- autoincrement
name  -- varchar
email  -- varchar

Member_Interest_Industry
=========================
memberId  -- fk reference to Member.id
industryId  -- fk reference to Industry.id

Member_Interest_Company
========================
memberId  -- fk reference to Member.id
companyId  -- fk reference to Company.id

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

SELECT a.name, a.email, c.name
FROM Member as a
JOIN Member_Interest_Company as b
ON b.memberId = a.id
JOIN Company as c
ON c.id = b.companyId
WHERE a.id = :inputParm
UNION 
SELECT a.name, a.email, d.name
FROM Member as a
JOIN Member_Interest_Industry as b
ON b.memberId = a.id
JOIN Company_Industry as c
ON c.industryId = b.industryId
JOIN Company as d
ON d.id = c.companyId
WHERE a.id = :inputParm
8 голосов
/ 24 февраля 2012

Вам следует изменить дизайн таблиц, как предлагали другие.

Однако, если не считать этого, вы можете сделать грубый хак:

SET sql_mode = 'ANSI';

    SELECT notify_members.id, notify_members.email
      FROM members notify_members
INNER JOIN members new_members
     WHERE CURRENT_DATE - new_members.date_activated <= 1
           AND
           new_members.company_industry RLIKE ('[[:<:]](' || REPLACE(notify_members.notify_industry, '-', '|') || ')[[:>:]]');

Тьфу. По сути, вы превращаете 9-13 в регулярное выражение MySQL [[:<:]](9|13)[[:>:]], которое соответствует 9, 13, 13-27-61 и т. Д., Но не соответствует 19-131 и т.п. (Это также поддерживает составное поле COMPANY_INDUSTRY.)

0 голосов
/ 29 февраля 2012

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

select m_to_notify.id, m_to_notify.email
from members m_to_notify
join members m_new_member
     on '-' || m_to_notify.notify_industry || '-'
     like '%-' || m_new_member.company_industry || '-%'
where datediff($today, m_new_memberdate_activated) <= 1)
0 голосов
/ 28 февраля 2012

Это может показаться немного уродливым, но вы можете попробовать следующее

ВНИМАНИЕ! Это сделает декартово произведение достойным любого Безумного ученого

SELECT NotifyIndustry.id,NotifyIndustry.email
FROM
(
    SELECT CONCAT('-',COMPANY_INDUSTRY,'-') company FROM members
    WHERE datediff($today, date_activated) <= 1)"
) CompanyIndustry
INNER JOIN
(
    SELECT CONCAT('-', NOTIFY_INDUSTRY,'-') who_to_notify
    FROM members
) NotifyIndustry
ON LOCATE(company,who_to_notify)>0;
0 голосов
/ 24 февраля 2012

Используйте синтаксис соединения SQL вместо стиля выбора. Вам необходимо присоединить таблицу участников к себе.

В настоящее время:

select id, email 
from members where notify_industry in 
  (select company_industry 
          from members 
           where datediff($today, date_activated) <= 1
  )

Используйте этот стиль:

select m1.id, m1.email 
from members m1 
inner join members m2 on m1.company_industry = m.notify_industry
where datediff($today, m2.date_activated) <= 1

Обратите внимание на использование псевдонимов для m1 и m2, чтобы понять, какие идентификаторы и электронные письма возвращаются.

...