私は過去2日間、このクエリで髪の毛を抜いてきており、他の2つの同様の投稿を運が悪かったので読んだり、もう一度読んだりしています。
シナリオ:ユーザーから2つの入力を収集しています。テストの送信時に使用したテストIDコードと電子メールアドレスです。テストコードは数字であり、最初に文字を含めることができますが、テスト機能はこの数字を省略する場合があるため、クエリの変数に文字を追加します(「newtidcode」の理由は以下に表示されます)。また、提出時に最大4つのメールアドレスをテスターに提供することもできます(4つのメールの可能性をテストする理由)。
これが私のクエリです:
$query->select($db->quoteName(array('tidcode', 'cdcode','email1', 'email2', 'email3', 'email4', 'status')))
->from($db->quoteName('#__tid_codes'))
->where($db->quoteName('tidcode').' = '.$db->quote($tidcode), 'OR')
->where($db->quoteName('tidcode').' = '.$db->quote($newtidcode), 'AND')
->where('('.$db->quoteName('email1').' = '.$db->quote($email).' OR '.$db->quoteName('email2').' = '.$db->quote($email).' OR '.$db->quoteName('email3').' = '.$db->quote($email).' OR '.$db->quoteName('email4').' = '.$db->quote($email).')');
ここで作成されたSQLステートメント:
SELECT `tidcode`,`cdcode`,`email1`,`email2`,`email3`,`email4`,`status` FROM `#__tid_codes` WHERE `tidcode` = '10348' OR `tidcode` = 'F10348' OR (`email1` = '[email protected]' OR `email2` = '[email protected]' OR `email3` = '[email protected]' OR `email4` = '[email protected]')
ご覧のとおり、ORは、Eメールが2番目の「where」ステートメントで指定されたANDである必要があります。前に、以下のような条件配列を使用しようとしても、同じことに遭遇しました。
$conditions1 = array(
$db->quoteName('tidcode')." = ".$db->quote($tidcode),
$db->quoteName('tidcode')." = ".$db->quote($newtidcode)
);
$conditions2 = array (
$db->quoteName('email1')." = ".$db->quote($email),
$db->quoteName('email2')." = ".$db->quote($email),
$db->quoteName('email3')." = ".$db->quote($email),
$db->quoteName('email4')." = ".$db->quote($email)
);
これは、この複雑さに対するJDatabaseクエリの私の最初の進出です。このアプリケーションは標準のHTMLとPHPで正常に動作していますが、Joomlaに移植しようとしています。どんな助けでも大歓迎です。
where
の2番目のパラメーターは$glue
と呼ばれ、期待どおりに機能しません。
これはwhere関数のソースコードです。
public function where($conditions, $glue = 'AND')
{
if (is_null($this->where))
{
$glue = strtoupper($glue);
$this->where = new JDatabaseQueryElement('WHERE', $conditions, " $glue ");
}
else
{
$this->where->append($conditions);
}
return $this;
}
クエリに追加した最初の "WHERE"の$ glueのみが必要であることがわかります。
この問題についてさらに詳しい情報を見つけました here が、情報が古くなっている可能性があります。
2つの変数$ conditions1と$ conditions2を保持し、次のようにクエリを作成します。
$query->select($db->quoteName(array('tidcode', 'cdcode','email1', 'email2', 'email3', 'email4', 'status')))
->from($db->quoteName('#__tid_codes'))
->where(implode(' OR ', $conditions1))
->where('(' . implode(' OR ', $conditions2) . ')');
これは、このクエリになります:
SELECT `tidcode`,`cdcode`,`email1`,`email2`,`email3`,`email4`,`status` FROM `#__tid_codes` WHERE `tidcode` = '10348' OR `tidcode` = 'F10348' AND (`email1` = '[email protected]' OR `email2` = '[email protected]' OR `email3` = '[email protected]' OR `email4` = '[email protected]')
これは少し厄介ですが、複雑な
where()
式につまずいたり、演算子の優先順位がわからない場合は、少なくとも1回はこのドキュメントを読んでください。
あなたの質問は、WHERE
句の条件をどのように評価すべきかについて少し曖昧です。このページは、言及するのに適した場所です Operator Precedence 。特に明記されていない限り、優先順位は必要に応じて機能しているとみなされます。
ただし、そのルールの影響について説明する前に、まずWHERE
句の3番目と最後の部分のロジック(メールのマッチング)を要約します。
_`email1` = '[email protected]'
OR `email2` = '[email protected]'
OR `email3` = '[email protected]'
OR `email4` = '[email protected]'
_
...もっと簡潔に書くことができます(D.R.Y。コーディング慣行):
_'[email protected]' IN (`email1`, `email2`, `email3`, `email4`)
_
次に、演算子の優先順位をその圧縮式を使用して示します。
A
はtidcode
の比較になりますB
はnewtidcode
の比較になりますC
はemail
の比較になります[〜#〜]および[〜#〜]は[〜#〜]または[〜の前に評価されます#〜]s(前のハイパーリンクを参照)
_A OR B AND C
_はA OR (B AND C)
と同じです...そして、それがあなたの望んでいることだと思います。
_A OR B
_を_AND C
_の前に評価したい場合は、_(A OR B) AND C
_のように括弧で明示する必要があります。
つまり、2つの異なるJoomla構文ソリューションを提供します。
単一のWHEREメソッド呼び出し:(多くの行幅ですが、生のSQLのように読み取ります)
_->where("tidcode = " . $db->q($tidcode) . " OR tidcode = " . $db->q($newtidcode) . " AND " . $db->q($email) . " IN (email1, email2, email3, email4)");
_
2つのWHEREメソッド呼び出し:(行の幅を減らしましたが、生のSQLのようには見えません)
_->where("tidcode = " . $db->q($tidcode), "OR")
->where("tidcode = " . $db->q($newtidcode) . " AND " . $db->q($email) . " IN (email1, email2, email3, email4)");
_
どちらも生成します:
_WHERE tidcode = '10348' OR tidcode = 'F10348' AND '[email protected]' IN (email1, email2, email3, email4)
_
比較のため、次のスニペットは最初にOR
を評価します!:
_->where("tidcode = " . $db->q($tidcode))
->extendWhere("OR", "tidcode = " . $db->q($newtidcode))
->extendWhere("AND", $db->q($email) . " IN (email1, email2, email3, email4)");
_
そして
_->where("tidcode = " . $db->q($tidcode))
->orWhere("tidcode = " . $db->q($newtidcode))
->andWhere($db->q($email) . " IN (email1, email2, email3, email4)");
_
生成する($query->dump()
を使用):
_WHERE ( (tidcode = '10348') OR (tidcode = 'F10348')) AND ('[email protected]' IN (email1, email2, email3, email4))
_
...[〜#〜]しかし[〜#〜]、もしあなたが[〜#〜]するなら[〜#〜]は最初にOR
を評価し、次にIN
を使用してWHERE句の最初の2つの条件を再パッケージ化します。
_->where(
array(
"tidcode IN (" . implode(", ", $db->q(array($tidcode, $newtidcode))) . ")",
$db->q($email) . " IN (email1, email2, email3, email4)"
)
);
_
生成されるもの:
_WHERE tidcode IN ('10348', 'F10348') AND '[email protected]' IN (email1, email2, email3, email4)
_