簡體   English   中英

MySQL連接三個表並搜索在一個表中找到的幾個關鍵字

[英]mySQL join three tables and search on several keywords found in one table

我試圖通過避免包含相同單詞的多個記錄來限制數據庫的大小,因此我建立了兩個表,用於將關鍵字與其他表中的行相關聯。

例如,我們使用以下搜索輸入:“找到我”

希望得到什么,這是product_id = 106中的product_name。我可以僅搜索產品名稱嗎? 否,因為產品可以與其他關鍵字(不屬於product_name的一部分)相關聯。

表格:ec_products

product_id    | product_name    | is_deleted
---------------------------------------------
106           | some product    | 0

表格:ec_keywords_index

word_id       | keyword
---------------------------------------------
55            | find
61            | my
77            | product

表格:ec_keyword_relations

word_id       | application_id    | related_id
------------------------------------------------
55            | 1                 | 106
61            | 1                 | 106
77            | 1                 | 106

因此,當我在搜索輸入中輸入“ find my”時,我現在想要的是:

  • 我只想要ec_keyword_relations.application_id = 1的匹配
  • 我的搜索字符串中的所有單詞都應與產品有關。 例如,如果我將搜索輸入更改為“查找褲子”,則不應找到product_id = 106。

這是到目前為止我已經嘗試過的方法(並且我知道我暫時還沒有一個可行的解決方案):

    $searchInput = 'find my';
    $keywords = explode(' ', $searchInput);

    $keyword_count = count($keywords);

    $n = 1;
    $query = '';

    foreach($keywords as $keyword) { 
        if ($n !== $keyword_count) { 
            $query_ext = ' AND ';
        } else { 
            $query_ext = ''; 
        } 

        $query .= "(ec_keywords_index.keyword LIKE '%$keyword%')" . $query_ext;

        ++$n;
    }

    $query = "
        SELECT 
            ec_products.product_name

        FROM 
            ec_products

        LEFT JOIN ec_search_word_relations
            ON ec_keyword_relations.related_id = ec_products.product_id

        LEFT JOIN ec_keywords_index
            ON ec_keywords_index.word_id = ec_keyword_relations.word_id

        WHERE 
            ($query) 
        AND 
            ec_products.is_deleted = '0' 
        AND 
            ec_keyword_relations.application_id = '1'

        GROUP BY
            ec_products.product_id

        ORDER BY 
            ec_products.product_name ASC 

        LIMIT 
            100";

    $stmt = $mysqli->prepare($query);
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($name);
    while ($stmt->fetch()) {
        echo $name;
    }

更新:

經過一番擺弄之后,我想出了可以按預期工作的解決方案。 (就性能而言)是好的還是壞的解決方案?

    $searchInput = 'find my';
    $keywords = explode(' ', $searchInput);

    $keyword_count = count($keywords);

    $n = 1;
    $where_query = '';
    $having_query = '';

    foreach($keywords as $keyword) { 
        if ($n != $keyword_count) {
            $w_query_ext = ' OR '; 
            $h_query_ext = ' AND ';
        } else { 
            $w_query_ext = ''; 
            $h_query_ext = ''; 
        }

        $where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext;

        $having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext;

        ++$n;
    }

    $query = "
        SELECT 
            ec_products.product_name, 
            GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'

        FROM 
            ec_products, 
            ec_keywords_index

        LEFT JOIN 
            ec_keyword_relations 
            ON ec_keyword_relations.word_id = ec_keywords_index.word_id

        WHERE ($where_query) 
            AND ec_products.product_id = ec_keyword_relations.related_id 
            AND ec_keyword_relations.application_id = '1' 
            AND ec_products.is_deleted = '0'

        GROUP BY 
            ec_products.product_name

        HAVING 
            ($having_query)

        LIMIT 
            100";

    $stmt = $mysqli->prepare($query);
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($name);
    while ($stmt->fetch()) {
        echo $name;
    }

上面的示例輸出如下查詢:

    SELECT 
        ec_products.product_name, 
        GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'

    FROM 
        ec_products, 
        ec_keywords_index

    LEFT JOIN 
        ec_keyword_relations 
        ON ec_keyword_relations.word_id = ec_keywords_index.word_id

    WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%') 
        AND ec_products.product_id = ec_keyword_relations.related_id 
        AND ec_keyword_relations.application_id = '1' 
        AND ec_products.is_deleted = '0'

    GROUP BY 
        ec_products.product_name

    HAVING 
        (related_keywords LIKE '%find%' AND related_keywords LIKE '%my%')

    LIMIT 
        100

我正在使用GROUP_CONCAT創建一個包含與產品相關的所有關鍵字的列,然后使用我的WHERE子句僅選擇在搜索字符串中實際找到的關鍵字...然后使用HAVING子句在該列中進行搜索使用GROUP_CONCAT構建。

擁有示例的答案:

經過一番擺弄之后,我想出了可以按預期工作的解決方案。 我不知道這是否是最佳做法,但它就像一個魅力。

    $searchInput = 'find my';
    $keywords = explode(' ', $searchInput);

    $keyword_count = count($keywords);

    $n = 1;
    $where_query = '';
    $having_query = '';

    foreach($keywords as $keyword) { 
        if ($n != $keyword_count) {
            $w_query_ext = ' OR '; 
            $h_query_ext = ' AND ';
        } else { 
            $w_query_ext = ''; 
            $h_query_ext = ''; 
        }

        $where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext;

        $having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext;

        ++$n;
    }

    $query = "
        SELECT 
            ec_products.product_name, 
            GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'

        FROM 
            ec_products, 
            ec_keywords_index

        LEFT JOIN 
            ec_keyword_relations 
            ON ec_keyword_relations.word_id = ec_keywords_index.word_id

        WHERE ($where_query) 
            AND ec_products.product_id = ec_keyword_relations.related_id 
            AND ec_keyword_relations.application_id = '1' 
            AND ec_products.is_deleted = '0'

        GROUP BY 
            ec_products.product_name

        HAVING 
            ($having_query)

        LIMIT 
            100";

    $stmt = $mysqli->prepare($query);
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($name);
    while ($stmt->fetch()) {
        echo $name;
    }

上面的示例輸出如下查詢:

    SELECT 
        ec_products.product_name, 
        GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'

    FROM 
        ec_products, 
        ec_keywords_index

    LEFT JOIN 
        ec_keyword_relations 
        ON ec_keyword_relations.word_id = ec_keywords_index.word_id

    WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%') 
        AND ec_products.product_id = ec_keyword_relations.related_id 
        AND ec_keyword_relations.application_id = '1' 
        AND ec_products.is_deleted = '0'

    GROUP BY 
        ec_products.product_name

    HAVING 
        (related_keywords LIKE '%find%' AND related_keywords LIKE '%my%')

    LIMIT 
        100

我正在使用GROUP_CONCAT創建一個包含與產品相關的所有關鍵字的列,然后使用我的WHERE子句僅選擇在搜索字符串中實際找到的關鍵字...然后使用HAVING子句在該列中進行搜索使用GROUP_CONCAT構建。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM