2010-01-11 13 views

Odpowiedz

30

ActiveRecord CodeIgniter nie obsługuje UNION, więc wystarczy napisać zapytanie i skorzystać z metody kwerendy ActiveRecord.

$this->db->query('SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2'); 
+7

Aby wyjaśnić, ActiveRecord CodeIgniter obsługuje tylko funkcje SQL, które są kompatybilne ze wszystkimi obsługiwanymi typami SQL (lub implementuje je na swój własny sposób). Ideą ActiveRecord jest abstrakcja typu bazy danych, która ma być niezależna od bazy danych i pozwolić użytkownikom na przejście z MySQL na MSSQL lub cokolwiek innego bez większego problemu. Gdyby spróbowali dodać unisono, wkręciłoby się z innymi typami baz danych. –

+0

Niezależna baza danych i niech ludzie przenoszą się z MySQL na MSSQL lub cokolwiek innego bez poważnego problemu – Louis

+3

Nazwij jeden popularny RDBMS, który nie obsługuje UNION? Inne ORMy (semantyka ActiveRecord), takie jak SQLAlchemy, oferują doskonałe wsparcie dla UNION-ów i JOIN (różnych rodzajów) we wszystkich bazach danych, w tym SQLite. W przypadku back-endów, które nie obsługują go bezpośrednio (np. SQLite), ORM sprawia, że ​​działa, wykonując trochę więcej zakulisów, jednocześnie zachowując przenośność. W tym konkretnym przypadku, wykonując zapytanie ręcznie, tracisz wszystkie pozory przenośności oraz bardziej zaawansowane funkcje samego systemu ActiveRecord (np. Filtrowanie tabel). – amcgregor

-1

Oto rozwiązanie stworzyłem:

$query1 = $this->db->get('Example_Table1'); 
$join1 = $this->db->last_query(); 
$query2 = $this->db->get('Example_Table2'); 
$join2 = $this->db->last_query(); 
$union_query = $this->db->query($join1.' UNION '.$join2.' ORDER BY column1,column2); 
+3

To naprawdę nie jest "serwer" wydajne, ponieważ wykonujesz 2 niepotrzebne zapytania przed UNION. –

+0

Mam rozwiązanie wydajne rozwiązanie i podałem odpowiedź. –

8

Możesz skorzystać z następujących metod, aby uzyskać SQL w modelu

$this->db->select('DISTINCT(user_id)'); 
$this->db->from('users_master'); 
$this->db->where('role_id', '1'); 

$subquery = $this->db->_compile_select(); 
$this->db->_reset_select(); 

ten sposób SQL będzie w zmienna podkwerendy $, bez faktycznego jej wykonywania.

Zadałeś to pytanie dawno temu, więc może masz już odpowiedź. jeśli nie, proces ten może załatwić sprawę.

+0

'_compile_select()' jest metodą chronioną w najnowszej wersji CodeIgniter (podkreślenie oznacza, że ​​była ona przeznaczona przede wszystkim jako metoda wewnętrzna). Zobacz moją odpowiedź na obejście: http://stackoverflow.com/a/14270008/560114 –

17

Wykonując połączenie za pomocą last_query(), może to utrudnić działanie aplikacji. Ponieważ dla pojedynczego związku wymagałoby to wykonania 3 zapytań. np. dla zapytań "n" związkowych "n + 1". Nie wpłynie to zbytnio na 1-2 połączenie zapytania. Ale da to problem, jeśli połączenie wielu zapytań lub tabel posiadających duże dane.

Ten link będzie Ci dużo: active record subqueries

Możemy połączyć aktywny rekord z ręcznymi zapytaniami. Przykład:

// #1 SubQueries no.1 ------------------------------------------- 

$this->db->select('title, content, date'); 
$this->db->from('mytable'); 
$query = $this->db->get(); 
$subQuery1 = $this->db->_compile_select(); 

$this->db->_reset_select(); 

// #2 SubQueries no.2 ------------------------------------------- 

$this->db->select('title, content, date'); 
$this->db->from('mytable2'); 
$query = $this->db->get(); 
$subQuery2 = $this->db->_compile_select(); 

$this->db->_reset_select(); 

// #3 Union with Simple Manual Queries -------------------------- 

$this->db->query("select * from ($subQuery1 UNION $subQuery2) as unionTable"); 

// #3 (alternative) Union with another Active Record ------------ 

$this->db->from("($subQuery1 UNION $subQuery2)"); 
$this->db->get(); 
+1

jaki jest pożytek z => '$ query = $ this-> db-> get();'? $ query nie wydaje się używać w dowolnym miejscu kodu. –

+0

Fantastyczne! Dobry pomysł. To prawdziwy związek. Drugi uruchamia 2 zapytania w bazie danych. Czasami zastanawiam się, czy deweloperzy dbają o wydajność bazy danych. –

22

Jest to szybki i brudny sposób ja kiedyś

// Query #1 

$this->db->select('title, content, date'); 
$this->db->from('mytable1'); 
$query1 = $this->db->get()->result(); 

// Query #2 

$this->db->select('title, content, date'); 
$this->db->from('mytable2'); 
$query2 = $this->db->get()->result(); 

// Merge both query results 

$query = array_merge($query1, $query2); 

Nie moja najlepsza praca, ale to rozwiązać mój problem.

Uwaga: Nie trzeba było zamawiać wyników.

+0

Dzięki za poprawną odpowiedź! –

+0

thx! najlepsza odpowiedź do teraz! – smashing

+1

Zły pomysł, jeśli dane zmieniają się w jakiś proces asynchroniczny, dane mogą zostać dodane/usunięte/zmienione między dwoma zapytaniami. – user9645

2

Znalazłem tej biblioteki, który pracował dobrze dla mnie, aby dodać Unii w stylu ActiveRecord:

https://github.com/NTICompass/CodeIgniter-Subqueries

ale miałem pierwszy (dostępny chwycić metodę z branży dev z CodeIgniter get_compiled_select() tutaj: https://github.com/EllisLab/CodeIgniter/blob/develop/system/database/DB_query_builder.php - DB_query_builder będzie zastępował DB_active_rec). Prawdopodobnie ta metoda będzie dostępna w przyszłej wersji produkcyjnej CodeIgniter.

Po dodaniu tej metody do DB_active_rec.php w systemie/bazie danych działało jak czar. (. Nie chciałem użyć wersji dev CodeIgniter ponieważ jest to aplikacja produkcja)

+0

Zrobiłem tę bibliotekę, dziękuję za jej użycie :-) –

+0

Jestem tutaj w dylemacie i potrzebuję wyjaśnienia. Czy dodanie metody 'get_compiled_select' w' DB_active_rec.php' spowoduje, że biblioteka będzie działać poprawnie? Czy musimy używać dodanej metody do łączenia wyników? Nie widzę żadnej wzmianki o tej metodzie w repozytorium GitHub biblioteki, o której wspomniałeś podczas wykonywania UNION. I czy wykona UNION ALL? – SilentAssassin

+0

@RocketHazmat: Zobacz powyższy komentarz i wyjaśnij moją wątpliwość. Nie mogę uruchomić zapytania UNION ALL zgodnie z twoim przykładem. – SilentAssassin

3

modyfikując Somnath huluks odpowiedź, dodam te następujące zmienne i funkcje klasy DB_Active_rec następująco:

class DB_Active_records extends CI_DB_Driver 
{ 

    .... 

    var $unions; 

    .... 

    public function union_push($table = '') 
    { 
     if ($table != '') 
     { 
      $this->_track_aliases($table); 
      $this->from($table); 
     } 

     $sql = $this->_compile_select(); 

     array_push($this->unions, $sql); 
     $this->_reset_select(); 
    } 

    public function union_flush() 
    { 
     $this->unions = array(); 
    } 

    public function union() 
    { 
     $sql = '('.implode(') union (', $this->unions).')'; 
     $result = $this->query($sql); 
     $this->union_flush(); 
     return $result; 
    } 

    public function union_all() 
    { 
     $sql = '('.implode(') union all (', $this->unions).')'; 
     $result = $this->query($sql); 
     $this->union_flush(); 
     return $result; 
    } 
} 

w związku z tym można praktycznie używać związków bez zależności do db_driver.

używać unii przy pomocy tej metody, po prostu tworzysz regularne aktywne zapytania rekordów, ale wywołuje union_push zamiast get.

uwaga: trzeba zapewnić wasze pytania mają pasujące kolumny jak zwykłe związki

przykład:

$this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file'); 
    $this->db->where(array('l.requirement' => 0)); 
    $this->db->union_push('lessons l'); 
    $this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file'); 
    $this->db->from('lessons l'); 
    $this->db->join('scores s', 'l.requirement = s.lid'); 
    $this->db->union_push(); 
    $query = $this->db->union_all(); 
    return $query->result_array(); 

przyniosłoby:

(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file` 
FROM `lessons` l 
WHERE `l`.`requirement`=0) 
union all 
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file` 
FROM `lessons` l 
JOIN `scores` s ON `l`.`requirement`=`s`.`lid`) 
1

próbować ten jeden

function get_merged_result($ids){     
    $this->db->select("column"); 
    $this->db->distinct(); 
    $this->db->from("table_name"); 
    $this->db->where_in("id",$model_ids); 
    $this->db->get(); 
    $query1 = $this->db->last_query(); 

    $this->db->select("column2 as column"); 
    $this->db->distinct(); 
    $this->db->from("table_name"); 
    $this->db->where_in("id",$model_ids); 

    $this->db->get(); 
    $query2 = $this->db->last_query(); 
    $query = $this->db->query($query1." UNION ".$query2); 

    return $query->result(); 
} 
+1

Zły pomysł, jeśli dane zmieniają się w jakiś proces asynchroniczny, dane mogą zostać dodane/usunięte/zmienione między dwoma zapytaniami. – user9645

1

To jest rozwiązanie, którego używam:

$union_queries = array(); 
$tables = array('table1','table2'); //As much as you need 
foreach($tables as $table){ 
    $this->db->select(" {$table}.row1, 
         {$table}.row2, 
         {$table}.row3"); 
    $this->db->from($table); 
    //I have additional join too (removed from this example) 
    $this->db->where('row4',1); 
    $union_queries[] = $this->db->get_compiled_select(); 
} 
$union_query = join(' UNION ALL ',$union_queries); // I use UNION ALL 
$union_query .= " ORDER BY row1 DESC LIMIT 0,10"; 
$query = $this->db->query($union_query);