http://docs.joomla.org/Selecting_data_using_JDatabase adresinde, JDatabase kullanarak bir alt sorgu yazmak için belgelenmiş bir yöntem yoktur.
https://Gist.github.com/gunjanpatel/86633 bunu gerçekleştirmenin bir yolunu gösterir (birkaç bit atlanmıştır):
$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);
Bu iyi ve makul bir yaklaşım gibi gözüküyor, ama daha iyi bir yaklaşım var mı?
Evet, söz konusu olduğunda, alt sorguyu oluşturma şekliniz, joomla'nın uzantı geliştiricilerinin çoğunluğu tarafından kabul edilen yöntemdir.
Aynı yöntemi bazı uzantılarım ve istemciler için yapılmış özel uzantılarımda kullanıyorum.
Bunu yapmanın "resmi" bir yolu yoktur, ancak gösterdiğiniz gibi yapmak, sorgu oluşturucuyu kullanmanıza ve yine de iyi miktarda okunabilirliği korumanıza olanak tanır
AFAIK, kolay alt sorgular yapmak için yerleşik bir yöntem değildir, bu muhtemelen sistemdeki bir eksikliktir ve PR aracılığıyla düzeltilmelidir.
Ancak, örneğinizle ilgili bir sorun görmüyorum - yeterince makul görünüyor.
~~~
Aşağıda @ DavidFritsch'in yorumuna yanıt olarak bir örnek verilmiştir. Bununla birlikte ne kadar çok düşünürsem, OP'de gösterilen daha basit yaklaşımı daha iyi seviyorum. Neler olduğu daha açık.
$query = $this->db->getQuery(true)
->select('a.*')
->subQuery()
->select('b.*')
->from('#__table_b AS b')
->as('subQueryResult')
->endSubQuery()
->from('#__table_a AS a');
Joomla Platform API'sını kullanarak alt sorgular içeren sorguları yürütmenin bir yolu da vardır. Alt sorguların nasıl kullanılacağına dair temel fikir gunjanpatel .
İç İçe Ayarlanmış Modeller üzerindeki sorguları yürütmek için bir örnek:
SQL sorgusu:
-- 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;
ve Joomla tarafından yürütülecek dönüştürülmüş sorgu:
// 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>";
Parçacığın versiyonunu sunacağım ve gerekçemi açıklayacağım ve Joomla Kodlama Standartları kılavuz ("queblock biçimlendirilmiş") tırnak işaretleri sunacağım.
$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);
Sorgu zincirini, bir dizi sorgu yöntemini birbiri ardına bağlamak için kullanın, her yöntem bir sonraki yöntemi destekleyebilen bir nesne döndürür, Bu, okunabilirliği artırır ve ortaya çıkan kodu basitleştirir.
İlk olarak en içteki sorguları yazıyorum ve en dıştaki sorguya ilerliyorum. Bu, tüm sorgu oluşturma yöntemlerini doğrudan getQuery()
yöntemine zincirlememe izin veriyor. Etkili olarak, değişken adı tek bir sorgu oluşturulurken yalnızca bir kez yazılır.
İşte bazı ağır sorgu yuvalamalarının müthiş bir örneği (zincirleme okları sıralamanın sevimli olduğunu düşündüğümde).
Aynı sorgu içinde birden fazla select()
ve/veya where()
çağrısı yapmaktan kaçınmaya çalışıyorum çünkü bunu gördüm daha az deneyimli geliştiricilerin karışıklığına yol açıyor . Bu yöntemler dizileri kabul ettiğinden, bunları kullanmak için daha okunabilir ve daha iyi kodlama uygulamaları buluyorum.
ve son olarak en tartışmalı konu ...
Tablo adları ve tablo sütun adları, tablo adından ve tablo sütunlarından kaçmak için her zaman quoteName () yöntemine eklenmelidir. Sorguda işaretlenen alan değerleri, veritabanına iletilmeden önce değerden kaçmak için her zaman quote () yöntemine eklenmelidir. Bir sorguda kontrol edilen tamsayı alan değerleri de (int) türüne dökülmelidir.
Bu duruş konusunda çok çatıştım. Geçen yıl Joomla'ya ilk geldiğimde, statik değerlerde işe yaramaz çağrılar yapmayacağım (sorgunun istikrarı, güvenliği, okunabilirliği için hiçbir fayda sağlamayacağım)! Ancak, işverenim Joomla hattına ayak basma fikrini seviyor ve genellikle kurallar için büyük bir takdir duyduğumu itiraf etmeliyim, bu yüzden quote()
, (int)
ve quoteName()
, aynı zamanda dize birleştirme yığınları anlamına gelir (tümü uygun aralıklarla). Çalışmamın son sonuçları korkunç bir şekilde şişirilmiş sorgu blokları olan ve hatta gözbebekimde zorlandım. Dikey istiflemeye borç vermeyen en kötü/en uzun hatlar, tablename, diğer ad, ON
, daha sonra gerektirebilecek veya gerekmeyebilecek bir veya daha fazla koşul nedeniyle join()
çağrılarıdır. alıntı yapmak. Bu politikanın acemi geliştiriciler için güvenlik göz önünde bulundurularak uygulandığını takdir edebilirim, ancak bu politikanın bir şekilde tüm Joomla kodlayıcılarının cahil kopyacı olmama duyarlılığıyla temperlenmesi durumunda eminim Yani, gereksiz aramalar olmadan kodun ne kadar temiz ve kısa göründüğüne bir göz atın.
Silme gelince:
*
Kullanmıyorum__toString()
çağrmıyorumASC
yazmıyorum çünkü bu varsayılan sıralama yönü