2012-02-15 17 views
1

私はmysqlクエリに取り組んでいます。条件付きで選択する

シナリオ:

私は、人々は、彼らが(NOTIFY_INDUSTRY)に興味のある業種を選択することができるウェブサイトを構築しています。選択した値を結合してデータベースフィールドに格納します。

例:メンバーは農業(id = 9)と石油とガス(id = 13)を選択します。私はそれらを9-13としてデータベースに登録します。 ユーザーは2つに限らず、複数の業界を選択できます。

また、メンバーは、データベースに格納されている情報技術を前提とした業界(COMPANY_INDUSTRY)を選択することもできます。

Sample table (members): 

ID 
EMAIL 
COMPANY_NAME 
COMPANY_INDUSTRY 
NOTIFY_INDUSTRY 

問題:

ウェブサイト上の新しいユーザー登録、メール(メールは毎日送信されます)新しいユーザーの業界(COMPANY_INDUSTRY)を持っている既存のユーザーに送信されるように関心のある業界の1つ(NOTIFY_INDUSTRY)。

は私がやっていること:これは、右のメンバーを選択しないと、私はそれについて

EDIT行くための正しい方法を知らない

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

- 現在の出力と正確な問題:

必要な場合でも、行は返されません。

新しいユーザーのcompany_industryが9であり、notify_industryの既存ユーザーが10-9-20であると仮定します。それは、新しいメンバーが既存のメンバーの関心のあるカテゴリにあるので、既存のメンバーの電子メールを返すことを意味します。空白が表示される

+1

期待どおりの結果を得ることができますか?あなたは現在正確になっている出力について何が間違っていますか? – JohnFx

+13

データベースを正規化する必要があります。 '9-13'を保存する代わりに、このシナリオでは2つの異なる行に' 9'と '13'を保存します。 –

+0

テーブルを正規化する最良の方法は何ですか?ユーザーが30種類のカテゴリに興味がある場合は、30種類の異なるカテゴリをテーブルの異なる30の行に挿入し、すべてのメンバーに対して同じ操作を行いますか?親切に説明してください –

答えて

8

他にも示唆しているように、テーブルを再設計する必要があります。

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-139,13,13-27-61などと一致するMySQL regular expression[[:<:]](9|13)[[:>:]]に変換しますが、19-131などと一致しません。これは少し醜い得ることができます

+0

Upvote。なぜなら、それは実際に実装すべき解決策ではないからです(あなたもそうは思わない)が、それは独創的なハックだからです。 –

+0

ありがとう、@MikeRyan。私は醜い/独創的なハッキングからいくつかのアップフォートを得ることを喜んで/悲しんでいます。 :) – pilcrow

+3

+1は、創造性とSQLはアート(美術==何かを見て、触れないでください)を示す – Eddy

12

@Shipluが指摘しているように、これは主に正規化の問題です。何人かの人々が考えると思われるものにもかかわらず、多価値の列は殺人右にしようとしています。

あなたの基本的な問題は次のとおりです。
あなたが一つ以上の業種に属する1つまたは複数の企業/業界に興味のあるメンバーを、持っています。あなたのテーブルの構造は、おそらくのように起動する必要があります。

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 
0

使用に参加スタイルでの選択ではなく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へのエイリアスを使用すると、返されるIDやメール理解するのに役立ちます。

+1

'notify_industry'は複数値の列なので、' JOIN'に変更すると効果がなくなります。あなたは結合の一部として(複数の) 'LIKE'述語を_attempt_追加することができますが、それは表を正規化するより複雑で高価になります –

0

(これは。あまりにも、化合物のCOMPANY_INDUSTRYフィールドをサポートしています)がありますが、これは

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

任意のマッドサイエンティストのデカルト積がふさわしいようになります次

警告を試みることができますおそらく最も速いクエリではないでしょうが、これは仕事をしなければなりません:

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) 
関連する問題