使用Union方法來查詢可以將兩個(gè)沒有實(shí)際關(guān)聯(lián)的數(shù)據(jù)表的查詢結(jié)果集進(jìn)行合并。使用UNION組合不同查詢的結(jié)果有時(shí)可能比使用WHERE子句的單個(gè)查詢快得多,尤其是當(dāng)查詢涉及到其他大表的聯(lián)接時(shí)。
為了使用union方法,你需要確認(rèn)你的SQL服務(wù)器是否支持。這些并不是Joomla強(qiáng)制要求的,但是如果你的SQL服務(wù)器不支持,那么執(zhí)行包含union語法的SQL時(shí),就會(huì)拋出數(shù)據(jù)庫(kù)錯(cuò)誤。另外,為了確保union執(zhí)行成功,每個(gè)SELECT查詢必須以相同的順序和兼容的數(shù)據(jù)類型返回相同數(shù)量的字段。
假設(shè)你有兩張表,一張是客戶表(#__zmax_customers),存儲(chǔ)了客戶的信息,一張是供應(yīng)商表(#__zmax_suppliers) 存儲(chǔ)了供應(yīng)商的信息。現(xiàn)在你需要同時(shí)給所有的客戶和供應(yīng)商發(fā)郵件。
獲得客戶的郵件列表SQL:
$db = JFactory::getDBO();
$query =$db->getQuery(true);
$query->select('name, email')->from('#__zmax_customers') ;
$mailList =$db->setQuery($query)->loadObjectList();
獲得供應(yīng)商的郵件列表SQL:
$db = JFactory::getDBO();
$query =$db->getQuery(true);
$query->select('name, email')->from('#__zmax_suppliers') ;
$mailList =$db->setQuery($query)->loadObjectList();
在這種情況下,你就可以使用Union方法來合并這兩個(gè)查詢了。代碼如下:
$db = JFactory::getDbo();
$query=$db->getQuery(true);
$query2 =$db->getQuery(true);
$query->select('name, email')->from('customers')
->union($query2->select('name , email')->from('suppliers'));
$mailList =$db->setQuery($query)->loadObjectList();
使用Union的查詢結(jié)果就會(huì)將上面兩個(gè)查詢的結(jié)果進(jìn)行合并,并且會(huì)移除掉重復(fù)的行。如果你不需要移除重復(fù)的行,那么可以使用unionAll 來代替union.
在Joomla中,union(unionAll) 方法支持多種方式來使用,可以使用SQL字符串,也可以使用JDatabaseQuery對(duì)象或者使用數(shù)組。假設(shè)我們有3個(gè)不同的查詢,代碼如下:
$q1->select('name, email')->from('customers');
$q2->select('name, email')->from('suppliers');
$q3->select('name, email')->from('shareholders');
下面的查詢都會(huì)返回相同的結(jié)果:
// 使用JDatabseQuery對(duì)象作為參數(shù).
$q1->union($q2)->union($q3);
// 使用JDatabaseQuery對(duì)象和字符串作為出納室
$q1->union($q2)->union('SELECT name, email FROM shareholders');
// 使用數(shù)組作為參數(shù)
$q1->union(array($q2,$q3));
// union查詢和主查詢的順序無關(guān),雖然我們這里使用q2作為主查詢,但返回結(jié)果和之前是一樣的
$q2->union(array($q1,$q3));
Joomla對(duì)SQL中UNION關(guān)鍵詞提交了3個(gè)方法:
在一些情況下,使用union替代 where in 或者 where or 能夠顯著的提高性能。
假設(shè)現(xiàn)在你有一個(gè)產(chǎn)品表,現(xiàn)在你想獲得兩個(gè)特定類別中的產(chǎn)品。通過代碼如下:
$query
->select('*')
->from('products')
->where('category = ' .$db->q('catA'),'or')
->where('category = ' .$db->q('catB'))
;
$products =$db->setQuery($query)->loadObjectList();
此時(shí),你使用Union來實(shí)現(xiàn),將會(huì)提高查詢的性能:
$query
->select('*')
->from('products')
->where('category = ' .$db->q('catA'))
;
$q2
->select('*')
->from('products')
->where('category = ' .$db->q('catB'))
;
$query->union($q2);
$products =$db->setQuery($query)->loadObjectList();
當(dāng)然,不僅僅是兩個(gè)分類,如果多個(gè)分類,你也可以u(píng)nion多個(gè)。
如果需要對(duì)結(jié)果集進(jìn)行排序,則需要了解當(dāng)前的SQL服務(wù)器是如果處理ORDER BY的。下面的代碼在MYSQL上運(yùn)行成功,但不保證在其他的數(shù)據(jù)庫(kù)上能運(yùn)行成功。
假設(shè)現(xiàn)在你想對(duì)輸出的結(jié)果集按照name字段進(jìn)行排序,帶么如下:
$q2->select('name , email')->from('suppliers');
$query->select('name, email')->from('customers')->union($q2)
->order('name')
;
$mailshot =$db->setQuery($query)->loadObjectList();
假設(shè)你想先對(duì)customer表的name排序,然后再對(duì)suppliers表的name排序,那么下面的SQL語句就不會(huì)按照你的希望返回結(jié)果:
$q2->select('name , email')->from('suppliers')
->order('name')
;
$query->select('name, email')->from('customers')
->order('name')
->union($q2)
;
$mailshot =$db->setQuery($query)->loadObjectList();
這是因?yàn)閱蝹€(gè)的SELECT 中使用 ORDER BY 不能對(duì)最終的查詢結(jié)果進(jìn)行排序, union查詢將會(huì)返回一個(gè)無序的結(jié)果集,上面的查詢語句沒有語法錯(cuò)誤,但是MYSQL的優(yōu)化器會(huì)忽略掉suppliers的 order By.而直接使用customers的order by為最終的結(jié)果排序。
解決問題的方法是增加一個(gè)用于排序的字段。代碼如下:
$q2
->select('name , email, 1 as sort_col')
->from('suppliers')
;
$query
->select('name, email, 2 as sort_col')
->from('customers')
->union($q2)
->order('sort_col, name')
;
$mailshot =$db->setQuery($query)->loadObjectList();
在某些情況下,我們需要使用order by 對(duì)單個(gè)select進(jìn)行排序,且不允許優(yōu)化器忽略。
假設(shè)您想向前10名客戶和前5名供應(yīng)商發(fā)送特別優(yōu)惠。這個(gè)時(shí)候在SELECT中就需要同時(shí)指定LIMIT子句與ORDER BY子句,查詢優(yōu)化程序?qū)⒉粫?huì)忽略順序。代碼如下:
$q2
->select('name , email, 1 as sort_col')
->from('suppliers')
->order('turnover DESC')
->setLimit(5)
;
$q1
->select('name, email, 2 as sort_col')
->from('customers')
->order('turnover DESC')
->setLimit(10)
;
$query
->select('name, email, 0 as sort_col')
->from('customers')
->where('1 = 0')
->union($q1)
->union($q2)
->order('sort_col, name')
;
$mailshot =$db->setQuery($query)->loadObjectList();
如果在重現(xiàn)此示例時(shí)遇到錯(cuò)誤,請(qǐng)檢查問題和相關(guān)補(bǔ)丁 Fixed wrong order of "UNION" and "ORDER BY"
更多建議: