ILKE查询中的多个字符串与数组与Postgres中的引用表

时间:2018-03-28 12:41:52

标签: sql postgresql sql-like

我的架构中有三个表:一个主表和两个引用表。 用户将搜索词(字符串)从AJAX传递到php到sql。

一个字符串查询很简单。两个或三个字符串查询(用逗号分隔,变成数组)要复杂得多......至少对我来说。我们的想法是搜索和过滤那些,因此每个返回必须包含 BOTH 字符串。不幸的是,这证明是困难的。它正在返回我想要的内容,但是当它是第一个或第二个列出 TWICE 的字符串时它也会返回。

这是我的代码:

SELECT DISTINCT a.document_id 
FROM main a 

INNER JOIN locations c 
  ON a.document_id = c.document_id 
    AND (c.street_address ILIKE any (array['%Benton%', '%Park%'])  
      OR c.location_name ILIKE any (array['%Benton%', '%Park%']) ) 

INNER JOIN names d ON a.document_id = d.document_id 
  AND (d.last_name ILIKE any (array['%Benton%', '%Park%'])  
    OR d.first_name ILIKE any (array['%Benton%', '%Park%']) ) 

  AND (a.document_id ILIKE any (array['%Benton%', '%Park%']) ) 
    OR a.title ILIKE any (array['%Benton%', '%Park%'])  
    OR a.description ILIKE ANY (array['%Benton%', '%Park%'])   

GROUP BY a.document_id HAVING COUNT(*) > 2 
ORDER BY a.document_id;

这里有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

@eurotrash - 你的问题实际上给了我一个想法。答案不仅在SQL中,而且在PHP循环中。我无法为每个查询加入所有表,因此我必须根据命中计数过滤哪些搜索。这是我的解决方案:

function searchArray($a, $b) {
    $cnt = count($a);
    $sqlArr = array();
    $lastOne = end($b);
    $valCnt = 0;
    $qArr = array();
    foreach ($b as $x => $x_value) {
        $valCnt++;
        $docCnt = $a[$x]['doccount'];
        $LocCnt = $a[$x]['loccount'];
        $PeepCnt = $a[$x]['namecount'];
        $val = pg_escape_string($x_value);
        $brac = "'%" . pg_escape_string($val) . "%'";
        $haveCnt = "";
        if ($docCnt == 0 && $LocCnt == 0 && $PeepCnt == 0) {
            return;
        }
            $haveCnt = sprintf("GROUP BY t.document_id HAVING COUNT(*) > $cnt - 1");
        $andOR = "";
        $cntZero = array_filter($a[$x], function($value) {
            return $value > 0;
        });
        $cntTheCnt = count($cntZero) >= 2 ? true : false;
        if ($cntTheCnt == false) {
            $andOR = "WHERE";
        } else {
            $andOR = "AND";
        }

        $subQuery = sprintf(" SELECT DISTINCT a$valCnt.document_id"
                . " FROM archive_main a$valCnt");

        $locJoin = sprintf(" INNER JOIN archive_locations f$valCnt"
                . " ON a$valCnt.document_id = f$valCnt.document_id");

        $locFind = sprintf(" %s f$valCnt.street_address ILIKE %s"
                . " OR f$valCnt.location_name ILIKE %s ", $andOR, $brac, $brac);

        $nameJoin = sprintf(" INNER JOIN archive_names b$valCnt"
                . " ON a$valCnt.document_id = b$valCnt.document_id");

        $nameFind = sprintf(" %s (b$valCnt.last_name ILIKE %s"
                . " OR b$valCnt.first_name ILIKE %s) ", $andOR, $brac, $brac);
        $nameFind .= "OR (FORMAT('%s %s', b$valCnt.first_name, b$valCnt.last_name) ILIKE $brac)";

        $whereDoc = sprintf(" %s a$valCnt.document_id ILIKE %s"
                . " OR a$valCnt.title ILIKE %s"
                . " OR a$valCnt.description ILIKE %s", $andOR, $brac, $brac, $brac);
        $find = "";
        $union = "";
        $joins = "";
        if ($LocCnt != 0) {
            $find .= $locFind;
            $joins .= $locJoin;
        }
        if ($PeepCnt != 0) {
            $find .= $nameFind;
            $joins .= $nameJoin;
        }
        if ($docCnt != 0) {
            $find .= $whereDoc;
        }
        if ($x_value != $lastOne) {
            $union .= sprintf(" UNION ALL ");
        } else {
            $union .= sprintf("");
        }
        array_push($qArr, $subQuery, $joins, $find, $union);
    }
    $boom = implode(' ', $qArr);
    $mainQuery = sprintf("SELECT DISTINCT t.document_id FROM (%s) as t %s
                            order by t.document_id;", $boom, $haveCnt);
    $sql = pg_query($mainQuery);
    if (!$sql) {
        $errrormsge = pg_last_error();
        print_r("$errrormsge - An error occurred during your query.");
        exit;
    }
    return($sql);
}

效果很好。