it-swarm-id.com

Metode untuk membuat subquery menggunakan JDatabase

Di http://docs.joomla.org/Selecting_data_using_JDatabase , tidak ada metode yang terdokumentasi untuk menulis subquery menggunakan JDatabase.

https://Gist.github.com/gunjanpatel/86633 mencontohkan satu cara untuk mencapai ini dengan (beberapa bit dihilangkan):

$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);

Ini sepertinya pendekatan yang bagus dan masuk akal, tetapi adakah yang lebih baik?

31
betweenbrain

Ya, sejauh yang saya ketahui, cara Anda membangun subquery adalah yang diadopsi oleh mayoritas pengembang ekstensi joomla.

Saya menggunakan metode yang sama pada beberapa ekstensi saya dan ekstensi khusus yang dibuat untuk klien.

Tidak ada cara "resmi" untuk melakukan ini, tetapi melakukannya seperti yang Anda tunjukkan memungkinkan Anda menggunakan pembuat kueri dan masih mempertahankan jumlah keterbacaan yang baik

16
Skullbock

AFAIK tidak ada cara bawaan untuk melakukan subkueri mudah, yang mungkin merupakan kekurangan dalam sistem dan harus diperbaiki melalui PR.

Namun, saya tidak melihat masalah dengan contoh Anda - tampaknya cukup masuk akal.

~~~

Berikut adalah contoh dalam menanggapi komentar @ DavidFritsch di bawah ini. Semakin saya memikirkannya, semakin baik saya menyukai pendekatan yang lebih sederhana yang ditampilkan di OP. Lebih jelas apa yang terjadi.

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

Ada juga cara untuk mengeksekusi kueri yang berisi subkueri menggunakan Joomla Platform API. Ide dasar tentang cara menggunakan subqueries didasarkan pada gunjanpatel .

Berikut ini adalah contoh untuk mengeksekusi kueri pada Nested Set Models :

Permintaan 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;

dan kueri yang diubah untuk dieksekusi oleh 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>";
3
Mario Neubauer

Saya akan menawarkan versi snippet saya kemudian jelaskan justifikasi saya dan sertakan kutipan dari manual Standar Coding Joomla (yang akan diformat dengan tanda kutip terbuka).

$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);

Gunakan rantai kueri untuk menghubungkan sejumlah metode kueri, satu demi satu, dengan setiap metode mengembalikan objek yang dapat mendukung metode berikutnya, ini meningkatkan keterbacaan dan menyederhanakan kode yang dihasilkan.

  • Saya menulis kueri paling dalam terlebih dahulu dan maju ke kueri terluar. Ini memungkinkan saya untuk menghubungkan semua metode pembuatan kueri langsung ke metode getQuery(). Secara efektif, nama variabel hanya ditulis sekali saat membangun permintaan individu.
    Ini contoh hebat dari beberapa permintaan bersarang yang berat (ketika saya pikir itu lucu untuk berbaris panah chaining).

  • Saya mencoba menghindari membuat beberapa panggilan select() dan/atau where() dalam query yang sama karena saya telah melihatnya menyebabkan kebingungan pengembang yang kurang berpengalaman . Karena metode ini menerima array, saya merasa lebih mudah dibaca dan praktik pengkodean yang lebih baik untuk menggunakannya.

  • dan akhirnya topik yang paling kontroversial ...

    Nama tabel dan nama kolom tabel harus selalu dilampirkan dalam metode quoteName () untuk menghindari nama tabel dan kolom tabel. Nilai bidang yang diperiksa dalam kueri harus selalu dilampirkan dalam metode quote () untuk menghindari nilai sebelum meneruskannya ke database. Nilai-nilai bidang integer yang diperiksa dalam kueri juga harus diketikkan ke (int).

    Saya sangat bertentangan dengan pendirian ini. Ketika saya pertama kali datang ke Joomla tahun lalu, saya pikir, saya tidak akan membuat panggilan yang tidak berguna (tidak ada manfaat untuk stabilitas, keamanan, keterbacaan permintaan) pada nilai statis! Namun, majikan saya menyukai ide mengikuti garis Joomla, dan saya harus mengakui bahwa saya umumnya memiliki apresiasi yang tinggi untuk aturan, jadi saya telah menyembunyikan pertanyaan saya dengan quote(), (int), dan quoteName() yang juga berarti tumpukan rangkaian string (semua berjarak dengan benar). Hasil akhir dari pekerjaan saya adalah blok permintaan yang membengkak secara mengerikan yang bahkan saya mengalami kesulitan mengamati. Baris terburuk/terpanjang yang tidak cocok untuk penumpukan vertikal adalah panggilan join() karena nama tab, alias, ON, maka satu atau beberapa kondisi yang mungkin atau mungkin tidak memerlukan mengutip. Saya dapat menghargai bahwa kebijakan ini diterapkan dengan mempertimbangkan keamanan bagi pengembang pemula, tapi saya yakin akan suka jika kebijakan ini entah bagaimana marah dengan sensibilitas bahwa tidak semua pembuat kode Joomla adalah penyalin copy-pastor yang bodoh Maksudku, lihat bagaimana bersih dan singkat kode terlihat tanpa panggilan yang tidak perlu.

  • Adapun pembersihan:

    • Saya hampir tidak pernah menggunakan * Pada klausa SELECT saya
    • Saya tidak pernah memanggil __toString()
    • Saya tidak mengutip bilangan bulat, saya menyebutnya bilangan bulat
    • Saya tidak menulis ASC karena itu adalah arah penyortiran default
    • Saya berusaha keras untuk tidak menggunakan kata kunci mysql saat membuat nama tabel dan nama kolom baru
    • Sebagai pilihan pribadi, saya cenderung menggunakan kuotasi ganda pada argumen string metode saya untuk menjaga keseragaman, membedakan dari kuotasi tunggal mysql, dan agar saya dapat menikmati interpolasi variabel yang biasanya saya tulis dengan " sintaksis kompleks ".
    • Saya menggunakan nama variabel informatif dan berkomentar untuk membantu keterbacaan kueri saya yang bersarang, dan kode saya secara umum
    • Saya menguji kode saya sebelum meninggalkan hak asuh saya
1
mickmackusa