it-swarm.dev

Metodo per la creazione di una sottoquery mediante JDatabase

Su http://docs.joomla.org/Selecting_data_using_JDatabase , non esiste un metodo documentato per scrivere una sottoquery usando JDatabase.

https://Gist.github.com/gunjanpatel/86633 esemplifica un modo per ottenere ciò con (alcuni bit omessi):

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

Sembra un approccio valido e plausibile, ma ce n'è uno migliore?

31
betweenbrain

Sì, per quanto mi riguarda, il modo in cui hai creato la subquery è quello adottato dalla maggior parte degli sviluppatori di estensioni di joomla.

Uso lo stesso metodo su alcune delle mie estensioni ed estensioni personalizzate create per i clienti.

Non esiste un modo "ufficiale" per farlo, ma farlo come hai mostrato ti consente di utilizzare il generatore di query e mantenere comunque una buona quantità di leggibilità

16
Skullbock

AFAIK non esiste un modo integrato per eseguire semplici subquery, il che è probabilmente una carenza nel sistema e dovrebbe essere corretto tramite PR.

Tuttavia, non vedo alcun problema con il tuo esempio: sembra abbastanza ragionevole.

~~~

Ecco un esempio in risposta al commento di @ DavidFritsch di seguito. Più ci penso, meglio mi piace l'approccio più semplice visualizzato nel PO. È più chiaro cosa sta succedendo.

$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

C'è anche un modo per eseguire query che contengono sottoquery utilizzando l'API della piattaforma Joomla. L'idea di base su come utilizzare le subquery si basa su gunjanpatel .

Ecco un esempio per l'esecuzione di query su Modelli di set nidificati :

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

e la query trasformata che verrà eseguita da 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

Offrirò la mia versione dello snippet, poi spiegherò la mia giustificazione e includerò le citazioni dal manuale di Joomla Coding Standards (che sarà formattato con il blocco delle virgolette).

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

Utilizzare il concatenamento di query per connettere una serie di metodi di query, uno dopo l'altro, con ciascun metodo che restituisce un oggetto in grado di supportare il metodo successivo. Ciò migliora la leggibilità e semplifica il codice risultante.

  • Scrivo prima le query più interne e procedo alla query più esterna. Ciò mi consente di concatenare tutti i metodi di creazione delle query direttamente al metodo getQuery(). In effetti, il nome della variabile viene scritto una sola volta durante la creazione della singola query.
    Ecco n fantastico esempio di nidificazione di query pesanti (quando ho pensato che fosse carino allineare le frecce incatenate).

  • Cerco di evitare di effettuare più chiamate select() e/o where() all'interno della stessa query perché l'ho vista porta alla confusione degli sviluppatori meno esperti . Poiché questi metodi accettano array, trovo più leggibile e una migliore pratica di codifica impiegarli.

  • e infine l'argomento più controverso ...

    I nomi delle tabelle e i nomi delle colonne della tabella devono sempre essere racchiusi nel metodo quoteName () per evitare il nome della tabella e le colonne della tabella. I valori dei campi controllati in una query devono sempre essere racchiusi nel metodo quote () per evitare il valore prima di passarlo al database. I valori dei campi interi controllati in una query devono anche essere digitati su (int).

    Sono molto in conflitto su questa posizione. Quando sono arrivato a Joomla l'anno scorso, ho pensato, non ho intenzione di fare chiamate inutili (nessun vantaggio per la stabilità, la sicurezza, la leggibilità della query) su valori statici! Tuttavia, al mio datore di lavoro piace l'idea di utilizzare la linea Joomla e devo ammettere che in genere apprezzo molto le regole, quindi ho eliminato le mie domande con quote(), (int) e quoteName() che significa anche un sacco di concatenazioni di stringhe (tutte correttamente distanziate). I risultati finali del mio lavoro sono blocchi di query orrendamente gonfiati che anche io faccio fatica a guardare negli occhi. Le linee peggiori/più lunghe che non si prestano allo stacking verticale sono le chiamate join() a causa del nome della scheda, dell'alias, ON, quindi una o più condizioni che possono o non possono richiedere citando. Posso apprezzare che questa politica è implementata pensando alla sicurezza per gli sviluppatori alle prime armi, ma mi piacerebbe sicuramente che questa politica fosse in qualche modo mitigata dalla sensibilità che non tutti i programmatori di Joomla sono ignoranti . Voglio dire, guarda come appare pulito e breve il codice senza le chiamate inutili.

  • Per quanto riguarda il rastrellamento:

    • Non uso quasi mai * Nelle mie clausole SELECT
    • Non chiamo mai __toString()
    • Non cito numeri interi, li lancio come numeri interi
    • Non scrivo ASC perché questa è la direzione di ordinamento predefinita
    • Faccio ogni sforzo per non usare le parole chiave mysql durante la creazione di nuovi nomi di tabelle e nomi di colonne
    • Per quanto riguarda le preferenze personali, tendo a usare la doppia virgoletta sugli argomenti di stringa del mio metodo per mantenere l'uniformità, distinguermi dalla virgoletta singola di mysql e in modo da poter godere dell'interpolazione variabile che scrivo tipicamente con " sintassi complessa ".
    • Uso nomi di variabili informativi e commenti per facilitare la leggibilità delle mie query nidificate e il mio codice in generale
    • Provo il mio codice prima che lasci la mia custodia
1
mickmackusa