JDatabase kullanarak bir alt sorgu oluşturma yöntemi


31

At http://docs.joomla.org/Selecting_data_using_JDatabase , JDatabase kullanarak bir alt sorgu yazmak için dokümante edilmiş bir yöntem yoktur.

https://gist.github.com/gunjanpatel/8663333 , bununla başa çıkmanın bir yolunu gösterir (birkaç bit atlandı):

$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, makul bir yaklaşım gibi görünüyor, ancak daha iyi bir yaklaşım var mı?


4
$ SubQuery'de toString () işlevini çağırmayı ihmal edebilirsiniz. Joomla! otomatik olarak sizin için idare edecek. Bunun dışında, aynı yöntemi kullanıyorum ve benim için iyi çalışıyor.
Zachary Draper


@ ZacharyDraper ilginç. Bundan sorumlu olan kodu gösterebilir misiniz?
Dmitry Rekun

3
@ ZacharyDraper: PHP (Joomla! Per se) sizin için kullanır ( __toString()) bir "sihir" yöntemidir.
MrWhite

Evet, teşekkürler w3d.
Zachary Draper

Yanıtlar:


16

Evet, endişelendiğim kadarıyla, alt sorguyu oluşturma şekliniz, joomla'nın uzantı geliştiricilerinin çoğunluğu tarafından benimsenen yoldur.

Aynı yöntemi bazı uzantılarım ve müşteriler için yapılan özel uzantılarımda da kullanıyorum.

Bunu yapmanın "resmi" bir yolu yoktur, ancak gösterdiğiniz şekilde yapmak sorgu oluşturucuyu kullanmanıza ve hala iyi bir miktarda okunabilirliği korumanıza izin verir


10

AFAIK, muhtemelen sistemde bir eksiklik olan ve PR ile düzeltilmesi gereken kolay sorgulama yapacak bir yol yoktur.

Ancak, örneğinizle ilgili hiçbir sorun görmüyorum - yeterince makul görünüyor.

~~~

Aşağıda @ DavidFritsch'in yorumuna yanıt olarak bir örnek verilmiştir. Ne kadar çok düşünürsem, OP'de görüntülenen daha basit yaklaşımı o kadar çok 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');

1
Bunun nasıl çalışması için herhangi bir fikrin var mı? Bu işi bir sorgu nesnesinde yapmak için kullanacağınız formatı hayal etmeye çalışıyorum ve hiçbir şey aslında bu yöntemden daha kolay hissettirmiyor.
David Fritsch

1
subQuerySelectBiraz daha "temiz" yapmanıza izin veren bir yöntem oluşturmak faydalı olabilir . Vereceğim cevabı ve örnek olarak düzenleyeceğim.
Don Gilbert,

Joomla
fruppel

3

Joomla Platform API'sini kullanarak alt sorgu içeren sorguları yürütmenin bir yolu da vardır. Alt sorguların nasıl kullanılacağı ile ilgili temel fikir gunjanpatel'e dayanmaktadır .

İşte İç İçe Set Modellerinde sorgu 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>";

1
İyi görünüyor, ancak kesinlikle OP'nin örneğindeki ile aynı: Önce alt sorguyu yapın ve sonra ana sorguda kullanın. Asıl soru, daha iyi bir yol olup olmadığıydı.
fruppel

1

Metin parçacığı sürümümü sunacağım sonra haklılığımı açıklayacağım ve Joomla Kodlama Standartları kılavuzundan alıntılar içereceğim (bunlar "formatlanmış" olacak).

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

Her biri bir sonraki yöntemi destekleyebilecek bir nesneyi döndürerek birbiri ardına bir dizi sorgu yöntemi bağlamak için Sorgu zincirini kullanın. Bu, okunabilirliği artırır ve ortaya çıkan kodu basitleştirir.

  • Önce en içteki sorguları yazıyorum ve en dıştaki sorguya ilerliyorum. Bu, tüm sorgu oluşturma yöntemlerini doğrudan getQuery()yönteme bağlamama izin verir . Etkili bir isim, bireysel sorgu oluşturulurken değişken ismi sadece bir kere yazılır.
    İşte bazı ağır sorgu iç içe geçme işlemine harika bir örnek ( zincirleme oklarını sıralamanın sevimli olduğunu düşündüğümde).

  • Aynı sorgu içinde birden fazla select()ve / veya where()çağrı yapmaktan kaçınmaya çalışıyorum çünkü daha az deneyimli geliştiricilerin karışıklığına yol açtığını gördüm . Bu yöntemler dizileri kabul ettiğinden, onları kullanmak için daha okunaklı ve daha iyi kodlama uygulaması buluyorum.

  • ve nihayet en tartışmalı konu ...

    Tablo adları ve tablo sütun adları, tablo adı ve tablo sütunlarından kaçmak için her zaman quoteName () yöntemine eklenmelidir. Bir sorguda kontrol edilen alan değerleri, veritabanına geçmeden önce değerden kaçmak için her zaman quote () yöntemine eklenmelidir. Bir sorguda kontrol edilen tamsayı alanı değerleri, cast (int) türünde de olmalıdır.

    Bu duruş konusunda çok çelişiyorum. Geçen yıl Joomla'ya ilk geldiğimde, statik değerlerle işe yaramaz çağrılar (istikrarın, güvenliğin, okunabilirliğin bir faydası olmaz) faydalanmayacağımı düşündüm. Ancak, benim işveren Joomla hattını toeing fikrini seviyor ve ben genelde kurallara için yüksek takdir itiraf etmeliyim ben ile benim sorguları hortumla yıkama edilmiş, böylece quote(), (int)ve quoteName()hangi zamanda tüm (string birleştirme yığınlar demektir düzgün aralıklı). Çalışmamın sonuçları, göz küresi zor bir zaman geçirdiğim bile, korkunç derecede şişirilmiş sorgu blokları olmam. Kendilerini dikey istiflemeye ödünç vermeyen en kötü / en uzun satırlar join(), tablo adı, takma ad ONve daha sonra alıntılama gerektirebilecek veya gerektirmeyecek bir veya daha fazla koşul nedeniyle yapılan çağrılardır .Bu politikanın acemi geliştiriciler için güvenlik gözetilerek uygulandığını takdir edebilirim, ancak bu politikanın bir şekilde Joomla kodlayıcılarının tümünün cahil kopyalayıcı olmadığına dair duyarlılığıyla temkinli olmasından memnuniyet duyarım. Yani, gereksiz çağrılar olmadan kodun ne kadar temiz ve kısa göründüğüne bir bakın.

  • Paspaslama gelince:

    • *SELECT cümlelerinde neredeyse hiç kullanmam
    • Ben hiç aramıyorum __toString()
    • Tamsayılardan alıntı yapmıyorum, onları tamsayı olarak kullanıyorum
    • Yazmıyorum ASCçünkü varsayılan sıralama yönü budur.
    • Yeni tablo adları ve sütun adları oluştururken mysql anahtar kelimeleri kullanmamak için her türlü çabayı gösteriyorum
    • Kişisel bir tercih olarak, tek biçimliliği korumak, mysql'in tek alıntıdan ayırt etmek için metodumun string argümanları üzerinde çift alıntı kullanmaya meyilliyim ve tipik olarak " karmaşık sözdizimi " ile yazdığım değişken enterpolasyonun tadını çıkarabilirim .
    • İç içe geçmiş sorgularımın okunabilirliğini ve genel olarak kodumu okumak için bilgilendirici değişken adları ve yorumlar kullanıyorum
    • Kodumu velayetimden çıkmadan önce test ederim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.