JDatabaseを使用してサブクエリを作成する方法


31

http://docs.joomla.org/Selecting_data_using_JDatabase、JDatabaseを使用してサブクエリを記述するための文書化の方法はありません。

https://gist.github.com/gunjanpatel/8663333は、これを実現する1つの方法を例示しています(いくつかのビットは省略)。

$subQuery = $db->getQuery(true);
$query    = $db->getQuery(true);

// Create the base subQuery select statement.
$subQuery->select('*')
    ->from($db->quoteName('#__sub_table'))
    ->where($db->quoteName('subTest') . ' = ' . $db->quote('1'));

// Create the base select statement.
$query->select('*')
    ->from($db->quoteName('#__table'))
    ->where($db->quoteName('state') . ' = ' . $db->quote('1'))
    ->where($db->quoteName('subCheckIn') . ' IN (' . $subQuery->__toString() . ')')
    ->order($db->quoteName('ordering') . ' ASC');

// Set the query and load the result.
$db->setQuery($query);

これは良い、もっともらしいアプローチのように思えますが、より良いアプローチはありますか?


4
$ subQueryでのtoString()の呼び出しを省略できます。Joomla!自動的に処理します。それとは別に、私はこの同じ方法を使用し、それは私のためにうまく機能しています。
ザカリードレーパー14


@ZacharyDraper興味深い。その原因となっているコードを表示できますか?
ドミトリーRekun 14

3
@ZacharyDraper:(Joomla!自体ではなく)PHPがそれを処理します(__toString())は「魔法の」メソッドです。
MrWhite 14

はい、w3dに感謝します。
ザカリードレーパー14

回答:


16

はい、私に関する限り、サブクエリの作成方法は、joomlaの拡張機能開発者の大多数が採用している方法です。

クライアント用に作成した拡張機能やカスタム拡張機能の一部で同じ方法を使用します。

これを行う「公式な」方法はありませんが、示したとおりに行うと、クエリビルダーを使用して、十分な読みやすさを維持できます。


10

私の知る限り、簡単なサブクエリを実行する方法は組み込まれていません。これはおそらくシステムの欠陥であり、PRで修正する必要があります。

しかし、私はあなたの例には何の問題も見ていません-十分に合理的だと思われます。

~~~

以下は、@ DavidFritschのコメントへの応答の例です。考えれば考えるほど、OPに表示されるよりシンプルなアプローチが好きになります。何が起こっているかはより明確です。

$query = $this->db->getQuery(true)
  ->select('a.*')
  ->subQuery()
    ->select('b.*')
    ->from('#__table_b AS b')
    ->as('subQueryResult')
  ->endSubQuery()
  ->from('#__table_a AS a');

1
これをどのように機能させることができるか考えていますか?1つのクエリオブジェクトでこの作業を行うために使用する形式を想像しようとしていますが、実際にはこの方法ほど簡単なものはありません。
デビッドフリッチュ14

1
subQuerySelectもう少し「きれいに」できるメソッドを作成する価値があるかもしれません。回答を編集して、例を提供します。
ドンギルバート14

私はそれをJoomlaで見たいです
fruppel

3

Joomla Platform APIを使用して、サブクエリを含むクエリを実行する方法もあります。サブクエリの使用方法に関する基本的な考え方は、gunjanpatelに基づいています

ネストされたセットモデルでクエリを実行する例を次に示します。

SQLクエリ:

-- Find the Immediate Subordinates of a Node
SELECT node.title, (COUNT(parent.id) - (sub_tree.depth + 1)) AS depth
FROM lubd3_usergroups AS node,
        lubd3_usergroups AS parent,
        lubd3_usergroups AS sub_parent,
        (
                SELECT node.id, (COUNT(parent.id) - 1) AS depth
                FROM lubd3_usergroups AS node,
                        lubd3_usergroups AS parent
                WHERE node.lft BETWEEN parent.lft AND parent.rgt
                        AND node.id = 1
                GROUP BY node.id
                ORDER BY node.lft
        )AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
        AND sub_parent.id = sub_tree.id
GROUP BY node.id
-- not showing the parent node
HAVING depth = 1
-- showing the parent node
-- HAVING depth <= 1
ORDER BY node.lft;

そして、Joomlaによって実行される変換されたクエリ:

// Create the subQuery select statement.
// Nested Set Queries: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
// CROSS JOIN: http://www.informit.com/articles/article.aspx?p=30875&seqNum=5
$subQuery->select(array('node.id', '(COUNT(parent.id) - 1) AS depth'))
    ->from($db->quoteName('#__usergroups') . 'node')
    ->join('CROSS', $db->quoteName('#__usergroups', 'parent'))
    ->where($db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('parent.lft') . ' AND ' . $db->quoteName('parent.rgt') . ' AND ' . $db->quoteName('node.id') . ' = ' . $db->quote('1'))
    ->group($db->quoteName('node.id'))
    ->order($db->quoteName('node.lft'));

// Create the base select statement.
$query->select(array('node.title', '(COUNT(parent.id) - (sub_tree.depth + 1)) AS depth'))
    ->from($db->quoteName('#__usergroups') . 'node')
    ->join('CROSS', $db->quoteName('#__usergroups', 'parent'))
    ->join('CROSS', $db->quoteName('#__usergroups', 'sub_parent'))
    ->join('CROSS', '(' . $subQuery .') AS sub_tree')
    ->where($db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('parent.lft') . ' AND ' . $db->quoteName('parent.rgt')
    . ' AND ' . $db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('sub_parent.lft') . ' AND ' . $db->quoteName('sub_parent.rgt')
    . ' AND ' . $db->quoteName('sub_parent.id') . ' = ' . $db->quoteName('sub_tree.id'))
    ->group($db->quoteName('node.id'))
    ->having($db->quoteName('depth') . ' = ' . $db->quote('1'))
    ->order($db->quoteName('node.lft'));

// Set the query and load the result.
$db->setQuery($query);
$rowList = $db->loadAssocList();

echo "<pre>";
print_r($rowList);
echo "</pre>";

1
よく見えますが、OPの例とまったく同じ方法です。最初にサブクエリを作成してから、メインクエリで使用します。問題は、より良い方法があるかどうかでした。
フラップ

1

スニペットのバージョンを提供してから、その正当性を説明し、Joomla Coding Standardsマニュアルからの引用を含めます(引用ブロック形式になります)。

$subquery = $db->getQuery(true)
    ->select("checkin")
    ->from("#__sub_table")
    ->where("subTest = 1");

$query = $db->getQuery(true)
    ->select("*")
    ->from("#__table")
    ->where([
        "state = 1",
        "subCheckIn IN ({$subQuery})"
    ])
    ->order("ordering");

$db->setQuery($query);

クエリチェーンを使用して、多くのクエリメソッドを次々に接続し、各メソッドが次のメソッドをサポートできるオブジェクトを返すようにします。これにより、可読性が向上し、結果のコードが簡素化されます。

  • 最初に最も内側のクエリを記述し、最も外側のクエリに進みます。これにより、すべてのクエリ構築メソッドをメソッドに直接チェーンできますgetQuery()。事実上、変数名は個々のクエリを構築するときに一度だけ書き込まれます。
    ここにありますいくつかの重いクエリの入れ子の素晴らしい例(私は連鎖する矢印を並べるためにかわいいと思ったとき)。

  • 同じクエリ内で複数の呼び出しselect()where()呼び出しを行わないようにします。経験の浅い開発者の混乱につながるためです。これらのメソッドは配列を受け入れるため、それらを使用する方が読みやすく、コーディングの実践が優れていると思います。

  • そして最後に最も物議を醸すトピック...

    テーブル名とテーブル列をエスケープするには、テーブル名とテーブル列名を常にquoteName()メソッドで囲む必要があります。クエリでチェックされるフィールド値は、quote()メソッドで常に囲まれ、データベースに渡す前に値をエスケープする必要があります。クエリでチェックされる整数フィールド値も(int)に型キャストする必要があります。

    私はこのスタンスで非常に対立しています。昨年Joomlaに初めて来たとき、静的な値に対して無用な呼び出し(クエリの安定性、セキュリティ、読みやすさのメリットはありません)を行うつもりはありませんでした!しかし、私の雇用者は、Joomlaのラインをトーのアイデアを好きで、私は私のクエリをダウンホースされているので、私は、私は一般的に、ルールのために高い評価を持っていることを認めざるを得ないquote()(int)quoteName()これも文字列連結の山を意味します(すべての適切な間隔)。私の仕事の最終結果は恐ろしく肥大化したクエリブロックであり、目をつぶるのに苦労しています。垂直スタッキングに役立たない最悪/最長の行join()は、テーブル名、エイリアス、ONおよび1つ以上の条件のための呼び出しです。このポリシーは初心者デベロッパー向けのセキュリティを念頭に置いて実装されていることは理解できますが、すべてのJoomlaコーダーが無知なコ​​ピーペーストではないという感性でこのポリシーが何らかの形で緩和された場合、私はそれを望みます。 つまり、不必要な呼び出しを行わずにコードがどれほど簡潔かつ簡潔に見えるかを見てみましょう。

  • モップアップについては:

    • *SELECT句ではほとんど使用しません
    • 私は電話しない __toString()
    • 整数を引用せず、整数としてキャストします
    • ASCそれがデフォルトのソート方向であるため、私は書きません
    • 新しいテーブル名と列名を作成するときにmysqlキーワードを使用しないようにあらゆる努力をします
    • 個人的な好みの問題として、メソッドの文字列引数に二重引用符を使用して均一性を維持し、mysqlの単一引用符と区別し、「複雑な構文」で一般的に記述する変数補間を楽しむことができます。
    • ネストされたクエリの読みやすさを高めるために、有益な変数名とコメントを使用します。コードは一般的に
    • 保護される前にコードをテストします
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.