【问题标题】:MySQL multiple JOIN clause with multiple WHEREMySQL 多个 JOIN 子句与多个 WHERE
【发布时间】:2014-05-30 09:01:41
【问题描述】:

这是第三次编辑。根据您的所有反馈,我能够使用多个搜索条件生成以下查询。

请注意,这是一个现有系统,存在预算问题,因此我正在尽我所能改进现有查询。您看到的搜索是基于数组手动完成的,并且没有连接。同样的搜索需要 2-3 分钟来处理,而感谢你们所有的摇滚大师,现在需要 7-8 秒来处理:)

SELECT SQL_CALC_FOUND_ROWS fname, lname, desig, company, region, state, country, add_uid, contacts.`id` as id
        FROM contacts
         INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id 
 AND ( 
contact_to_categories.catid = '2'
 ) 

 INNER JOIN contact_professional_details ON contact_professional_details.contact_id = contacts.id
 AND ( 
FIND_IN_SET('1', contact_professional_details.pd_insid)
 OR FIND_IN_SET(' 8', contact_professional_details.pd_insid)
 OR FIND_IN_SET(' 33', contact_professional_details.pd_insid)
 ) 

 AND ( 
FIND_IN_SET('4', contact_professional_details.pd_secid)
 OR FIND_IN_SET('3', contact_professional_details.pd_secid)
 OR FIND_IN_SET('5', contact_professional_details.pd_secid)
 OR FIND_IN_SET('7', contact_professional_details.pd_secid)
 OR FIND_IN_SET('12', contact_professional_details.pd_secid)
 OR FIND_IN_SET('11', contact_professional_details.pd_secid)
 OR FIND_IN_SET('9', contact_professional_details.pd_secid)
 OR FIND_IN_SET('38', contact_professional_details.pd_secid)
 OR FIND_IN_SET('35', contact_professional_details.pd_secid)
 OR FIND_IN_SET('115', contact_professional_details.pd_secid)
 ) 

 INNER JOIN contact_address ON contact_address.contact_id = contacts.id
 AND ( 
contact_address.hmregion IN ('AF', 'EU', 'OC', 'SA')
 OR contact_address.hmcountry IN ('Algeria', 'Angola', 'Benin', 'Comoros', 'Andorra', 'Austria', 'Belarus', 'Belgium', 'American Samoa', 'Australia', 'French Polynesia', 'Guam', 'Kiribati', 'Marshall Islands', 'Colombia', 'Ecuador', 'Falkland Islands', 'Guyana', 'Paraguay', 'Peru', 'Laos', 'Malaysia', 'Myanmar', 'Singapore', 'Vietnam')
 OR contact_address.hmcity = 'singapore'
 ) 

 INNER JOIN contact_offices ON contact_offices.contact_id = contacts.id
 AND ( 
contact_offices.off_region IN ('AF', 'EU', 'OC', 'SA')
 OR contact_offices.off_country IN ('Algeria', 'Angola', 'Benin', 'Comoros', 'Andorra', 'Austria', 'Belarus', 'Belgium', 'American Samoa', 'Australia', 'French Polynesia', 'Guam', 'Kiribati', 'Marshall Islands', 'Colombia', 'Ecuador', 'Falkland Islands', 'Guyana', 'Paraguay', 'Peru', 'Laos', 'Malaysia', 'Myanmar', 'Singapore', 'Vietnam')
 OR contact_offices.off_city = 'singapore'
 ) 


        WHERE 1 AND ( 
FIND_IN_SET('1', contacts.ins_id)
 OR FIND_IN_SET(' 8', contacts.ins_id)
 OR FIND_IN_SET(' 33', contacts.ins_id)
 )

 AND ( 
FIND_IN_SET('4', contacts.sec_id)
 OR FIND_IN_SET('3', contacts.sec_id)
 OR FIND_IN_SET('5', contacts.sec_id)
 OR FIND_IN_SET('7', contacts.sec_id)
 OR FIND_IN_SET('12', contacts.sec_id)
 OR FIND_IN_SET('11', contacts.sec_id)
 OR FIND_IN_SET('9', contacts.sec_id)
 OR FIND_IN_SET('38', contacts.sec_id)
 OR FIND_IN_SET('35', contacts.sec_id)
 OR FIND_IN_SET('115', contacts.sec_id)
 )

 AND ( FIND_IN_SET('Tier 1', `vip_tier`) OR FIND_IN_SET('Tier 3', `vip_tier`) )
 AND ( FIND_IN_SET('Tier A', `vip_coll_tier`) )
 AND ( FIND_IN_SET('Yes', `vip_influencer`) )
 AND ( FIND_IN_SET('Contemporary', `vip_class_art_coll`) OR FIND_IN_SET('Modern', `vip_class_art_coll`) OR FIND_IN_SET('Geographic', `vip_class_art_coll`) )
 AND ( FIND_IN_SET('Sculpture', `vip_med_art_coll`) OR FIND_IN_SET('Photography', `vip_med_art_coll`) OR FIND_IN_SET('Video', `vip_med_art_coll`) OR FIND_IN_SET('Installation', `vip_med_art_coll`) )
 AND ( FIND_IN_SET('Japan', `vip_geo_int`) OR FIND_IN_SET('Korea', `vip_geo_int`) OR FIND_IN_SET('Southeast Asia', `vip_geo_int`) OR FIND_IN_SET('Oceania', `vip_geo_int`) )
 AND ( FIND_IN_SET('HNWI', `vip_seniority`) OR FIND_IN_SET('Top Social Leaders', `vip_seniority`) OR FIND_IN_SET('Other Executives', `vip_seniority`) )
 AND ( `status` = 'a' )

        ORDER BY  fname
                    asc
        LIMIT 0, 50

我知道这可以通过将集合值中的查找移动到单独的表并在联系人主表和值主表之间创建关系表来进一步改进。但正如我所说,预算对这些人来说是个大问题,所以我想这对他们来说效率更高。

欢迎任何进一步的改进想法。

【问题讨论】:

  • 您在 ON 子句中有大量额外的括号和一些多余的 AND。
  • 使用IN 子句来减少您拥有的大量OR 条件。
  • ...并规范您的设计。说真的。
  • 请删除额外代码:从第 9 行到第 17 行 INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id AND (contact_to_categories.catid = '2') INNER JOIN contact_professional_details ON contact_professional_details.contact_id = Contacts.id AND ( ) INNER JOIN contact_professional_details ON contact_professional_details.contact_id = contacts.id AND (
  • 老实说,我根本不知道这个查询是如何工作的......

标签: mysql sql join inner-join where-clause


【解决方案1】:

这是在您的查询中给出错误的部分

INNER JOIN contact_professional_details 
ON contact_professional_details.contact_id = contacts.id
 AND (       <-- Here
INNER JOIN contact_to_categories 
ON contact_to_categories.contactid = contacts.id 
 AND (
contact_to_categories.catid = '2'
)

改成

INNER JOIN contact_professional_details 
ON contact_professional_details.contact_id = contacts.id

INNER JOIN contact_to_categories 
ON contact_to_categories.contactid = contacts.id 
 AND contact_to_categories.catid = '2'

编辑: 您发布的查询非常混乱,您确实多次加入同一个表,并且确实使用了链式 OR 条件而不是 IN 子句。因此,以下是您修改后的查询。

SELECT SQL_CALC_FOUND_ROWS fname, 
lname, 
desig, 
company, 
region, 
state, 
country, 
add_uid, 
contacts.`id` as id
FROM contacts

INNER JOIN contact_to_categories 
ON contact_to_categories.contactid = contacts.id 
AND contact_to_categories.catid = '2'

INNER JOIN contact_professional_details 
ON contact_professional_details.contact_id = contacts.id
 AND (
 FIND_IN_SET('4', contact_professional_details.pd_secid)
 OR FIND_IN_SET('3', contact_professional_details.pd_secid)
 OR FIND_IN_SET('5', contact_professional_details.pd_secid)
 OR FIND_IN_SET('7', contact_professional_details.pd_secid)
 OR FIND_IN_SET('12', contact_professional_details.pd_secid)
 OR FIND_IN_SET('11', contact_professional_details.pd_secid)
 OR FIND_IN_SET('9', contact_professional_details.pd_secid)
 OR FIND_IN_SET('38', contact_professional_details.pd_secid)
 OR FIND_IN_SET('35', contact_professional_details.pd_secid)
 OR FIND_IN_SET('115', contact_professional_details.pd_secid)
)

 INNER JOIN contact_address ON contact_address.contact_id = contacts.id
 AND 
contact_address.hmregion IN ('AF','EU','OC','SA')
AND 
contact_address.hmcountry IN ('Algeria',
'Angola',
'Benin',
'Comoros',
'Andorra',
'Austria',
'Belarus',
'Belgium',
'American Samoa',
'Australia',
'French Polynesia',
'Guam',
'Kiribati',
'Marshall Islands',
'Colombia',
'Ecuador',
'Falkland Islands',
'Guyana',
'Paraguay',
'Peru',
'Laos',
'Malaysia',
'Myanmar',
'Singapore',
'Vietnam'
)
AND contact_address.hmcity='singapore'

 INNER JOIN contact_offices ON contact_offices.contact_id = contacts.id
 AND 
contact_offices.off_region IN ('AF','EU','OC','SA')
AND
contact_offices.off_country IN ('Algeria',
 'Angola',
 'Benin',
 'Comoros',
 'Andorra',
 'Austria',
 'Belarus',
 'Belgium',
 'American Samoa',
 'Australia',
 'French Polynesia',
 'Guam',
 'Kiribati',
 'Marshall Islands',
 'Colombia',
 'Ecuador',
 'Falkland Islands',
 'Guyana',
 'Paraguay',
 'Peru',
 'Laos',
 'Malaysia',
 'Myanmar',
 'Singapore',
 'Vietnam'
)
AND contact_offices.off_city='singapore'



WHERE 1 AND (
FIND_IN_SET('1', contacts.ins_id)
 OR FIND_IN_SET(' 8', contacts.ins_id)
 OR FIND_IN_SET(' 33', contacts.ins_id)
 )

 AND (
FIND_IN_SET('4', contacts.sec_id)
 OR FIND_IN_SET('3', contacts.sec_id)
 OR FIND_IN_SET('5', contacts.sec_id)
 OR FIND_IN_SET('7', contacts.sec_id)
 OR FIND_IN_SET('12', contacts.sec_id)
 OR FIND_IN_SET('11', contacts.sec_id)
 OR FIND_IN_SET('9', contacts.sec_id)
 OR FIND_IN_SET('38', contacts.sec_id)
 OR FIND_IN_SET('35', contacts.sec_id)
 OR FIND_IN_SET('115', contacts.sec_id)
 )

 AND (FIND_IN_SET('Tier 1', `vip_tier`) OR FIND_IN_SET('Tier 3', `vip_tier`))
 AND (FIND_IN_SET('Tier A', `vip_coll_tier`))
 AND (FIND_IN_SET('Yes', `vip_influencer`))
 AND (FIND_IN_SET('Contemporary', `vip_class_art_coll`) OR FIND_IN_SET('Modern', `vip_class_art_coll`) OR FIND_IN_SET('Geographic', `vip_class_art_coll`))
 AND (FIND_IN_SET('Sculpture', `vip_med_art_coll`) OR FIND_IN_SET('Photography', `vip_med_art_coll`) OR FIND_IN_SET('Video', `vip_med_art_coll`) OR FIND_IN_SET('Installation', `vip_med_art_coll`))
 AND (FIND_IN_SET('Japan', `vip_geo_int`) OR FIND_IN_SET('Korea', `vip_geo_int`) OR FIND_IN_SET('Southeast Asia', `vip_geo_int`) OR FIND_IN_SET('Oceania', `vip_geo_int`))
 AND (FIND_IN_SET('HNWI', `vip_seniority`) OR FIND_IN_SET('Top Social Leaders', `vip_seniority`) OR FIND_IN_SET('Other Executives', `vip_seniority`))
 AND (`status`='a')

ORDER BY  fname asc
LIMIT 0,50

【讨论】:

  • 感谢您的帮助。现在将尝试调整查询生成器,并尽快通知你们。
  • 非常感谢您的帮助。欣赏!
  • @Kunal,那么是时候接受答案并欢迎了。
【解决方案2】:

当您有多个连接时,最好为您的表使用别名而不是全名。使阅读和理解更加容易。无论如何,请在您收到错误的第 9 行附近尝试此操作。

  INNER JOIN contact_professional_details
    ON contact_professional_details.contact_id = contacts.id
    INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id 
    AND contact_to_categories.catid = '2'

【讨论】:

    【解决方案3】:

    您的内部连接条件不正确。

    例如

    INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id
    AND
    (
        contact_to_categories.catid = '2'
    )
    

    需要

    INNER JOIN contact_to_categories ON (
            contact_to_categories.contactid = contacts.id
        AND contact_to_categories.catid = '2'
    )
    

    您需要修复所有遵循上述模式的内部连接

    【讨论】:

    • 好的,请注意。将尝试按照@geoand 的建议更正条件并添加表别名。将很快发布结果。感谢一吨大师。
    • 虽然原始代码是这样的乱七八糟,但像这样奇怪的地方的括号不会影响代码在这里的工作方式。但是像INNER JOIN contact_professional_details ON contact_professional_details.contact_id = contacts.id AND ( INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id AND ( contact_to_categories.catid = '2' ) 这样有一个额外的AND ( 的位(并且没有匹配的右括号)会导致重大问题
    • @geoand 感谢大师的帮助。感谢您的知识:)
    • @Kickstart 我更改了括号位置并添加了别名。现在编辑我的主要问题。查询现在运行完美,但有一个小问题。请参阅上面编辑过的问题。
    • 您好,我的另一个查询有问题。如果您能提供帮助,那就太好了。
    【解决方案4】:

    假设您对指定地区或指定国家或指定城市的联系人感兴趣,然后稍微清理一下您的代码:-

    SELECT SQL_CALC_FOUND_ROWS fname, lname, desig, company, region, state, country, add_uid, contacts.`id` as id
    FROM contacts
    INNER JOIN contact_to_categories ON contact_to_categories.contactid = contacts.id AND contact_to_categories.catid = '2'
    INNER JOIN contact_professional_details ON contact_professional_details.contact_id = contacts.id
    AND (
     FIND_IN_SET('4', contact_professional_details.pd_secid)
     OR FIND_IN_SET('3', contact_professional_details.pd_secid)
     OR FIND_IN_SET('5', contact_professional_details.pd_secid)
     OR FIND_IN_SET('7', contact_professional_details.pd_secid)
     OR FIND_IN_SET('12', contact_professional_details.pd_secid)
     OR FIND_IN_SET('11', contact_professional_details.pd_secid)
     OR FIND_IN_SET('9', contact_professional_details.pd_secid)
     OR FIND_IN_SET('38', contact_professional_details.pd_secid)
     OR FIND_IN_SET('35', contact_professional_details.pd_secid)
     OR FIND_IN_SET('115', contact_professional_details.pd_secid)
    )
    INNER JOIN contact_address ON contact_address.contact_id = contacts.id 
    INNER JOIN contact_offices ON contact_offices.contact_id = contacts.id 
    WHERE 1 
    AND ((
        contact_address.hmregion IN ('AF', 'EU', 'OC', 'SA')
        OR contact_address.hmcountry IN ('Algeria', 'Angola', 'Benin', 'Comoros', 'Andorra', 'Austria', 'Belarus', 'Belgium', 'American Samoa', 'Australia', 'French Polynesia', 'Guam', 'Kiribati', 'Marshall Islands', 'Colombia', 'Ecuador', 'Falkland Islands', 'Guyana', 'Paraguay', 'Peru', 'Laos', 'Malaysia', 'Myanmar', 'Singapore', 'Vietnam')
        OR contact_address.hmcity='singapore'
    )
    OR (
        contact_offices.off_region IN ('AF', 'EU', 'OC', 'SA')
        OR contact_offices.off_country IN ('Algeria', 'Angola', 'Benin', 'Comoros', 'Andorra', 'Austria', 'Belarus', 'Belgium', 'American Samoa', 'Australia', 'French Polynesia', 'Guam', 'Kiribati', 'Marshall Islands', 'Colombia', 'Ecuador', 'Falkland Islands', 'Guyana', 'Paraguay', 'Peru', 'Laos', 'Malaysia', 'Myanmar', 'Singapore', 'Vietnam')
        OR contact_offices.off_city='singapore'
    )
    )
    AND (
        FIND_IN_SET('1', contacts.ins_id)
        OR FIND_IN_SET(' 8', contacts.ins_id)
        OR FIND_IN_SET(' 33', contacts.ins_id)
    )
    AND (
        FIND_IN_SET('4', contacts.sec_id)
        OR FIND_IN_SET('3', contacts.sec_id)
        OR FIND_IN_SET('5', contacts.sec_id)
        OR FIND_IN_SET('7', contacts.sec_id)
        OR FIND_IN_SET('12', contacts.sec_id)
        OR FIND_IN_SET('11', contacts.sec_id)
        OR FIND_IN_SET('9', contacts.sec_id)
        OR FIND_IN_SET('38', contacts.sec_id)
        OR FIND_IN_SET('35', contacts.sec_id)
        OR FIND_IN_SET('115', contacts.sec_id)
    )
    AND (
        FIND_IN_SET('Tier 1', `vip_tier`) 
        OR FIND_IN_SET('Tier 3', `vip_tier`)
     )
    AND (FIND_IN_SET('Tier A', `vip_coll_tier`))
    AND (FIND_IN_SET('Yes', `vip_influencer`))
    AND (FIND_IN_SET('Contemporary', `vip_class_art_coll`) OR FIND_IN_SET('Modern', `vip_class_art_coll`) OR FIND_IN_SET('Geographic', `vip_class_art_coll`))
    AND (FIND_IN_SET('Sculpture', `vip_med_art_coll`) OR FIND_IN_SET('Photography', `vip_med_art_coll`) OR FIND_IN_SET('Video', `vip_med_art_coll`) OR FIND_IN_SET('Installation', `vip_med_art_coll`))
    AND (FIND_IN_SET('Japan', `vip_geo_int`) OR FIND_IN_SET('Korea', `vip_geo_int`) OR FIND_IN_SET('Southeast Asia', `vip_geo_int`) OR FIND_IN_SET('Oceania', `vip_geo_int`))
    AND (FIND_IN_SET('HNWI', `vip_seniority`) OR FIND_IN_SET('Top Social Leaders', `vip_seniority`) OR FIND_IN_SET('Other Executives', `vip_seniority`))
    AND (`status`='a')
    ORDER BY  fname asc
    LIMIT 0, 50
    

    请注意,使用 FIND_IN_SET 表明数据库的规范化程度很低,其中的字段包含逗号分隔的值列表。

    【讨论】:

    • 感谢您的帮助。真的很感激。
    • 已编辑正文。查询现在工作正常。欢迎任何进一步的建议。非常感谢你的帮助。干杯!
    • 您似乎已经用我建议的查询更新了您的原始问题。虽然可以改进,但这可能需要重新设计数据库。例如,您对 contacts.sec_id 使用 FIND_IN_SET 10 次。 FIND_IN_SET 效率不高,将逗号分隔的值列表从contacts.sec_id 中移出会更有效,而是将它们放入另一个表中,每个联系人每个id 一行。然后检查一个值可以使用索引。这同样适用于您使用 FIND_IN_SET 的大多数其他时间。
    猜你喜欢
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多