Pytanie MySQL Union Wszystko w domyślnym zakresie Yii


Używam Yii 1.1.16 i zastanawiałem się, w jaki sposób powinienem używać modelu Union 2 z domyślnym zasięgiem?

model 1 = abc
model 2 = abc2

w zasadzie chcę zrobić proste połączenie

SELECT * FROM `abc`
UNION ALL
SELECT * FROM `abc2`

Naprawdę nie używał domyślnego zakresu, tak nowego w koncepcji. Obie tabele mają dokładnie te same numery kolumn i nazwy kolumn.

próbowałem tego, ale nie udało mi się.

w moim abc Model

public function defaultScope() {
        return array(
            'alias' => 't2',
            'select'=>array('t.*, t2.*'),
            'union'=>array('SELECT * FROM `abc2`')
        );
    }

AKTUALIZACJA:  Właśnie zdałem sobie sprawę http://www.yiiframework.com/doc/api/1.1/CDbCriteria, nie ma union dla CDbCriteria.

public function defaultScope() {
        return array(
            //'alias' => 't',
            'select'=>array('*'),
            'join'=>'UNION ALL SELECT * FROM `abc2`'
        );
    }

powyższy kod daje mi błąd

CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 't.make_code' in 'where clause'. The SQL statement executed was: SELECT `t`.`class_code`, `t`.`make_code`, `t`.`model_code` FROM `abc` `t` UNION ALL SELECT * FROM `abc2` WHERE `t`.`make_code`=:yp0 LIMIT 1. Bound with :yp0='11' 

w obu tabelach mam kolumnę make_code

Potrzebuję kwerendy tak wyglądać

SELECT * FROM 
(
   SELECT * FROM `abc` 
      UNION ALL 
   SELECT * FROM `abc2`
) AS t 

jak to zrobić?


11
2018-01-15 03:42


pochodzenie


tak, trochę tego znalazłem. ale wciąż próbuję to rozgryźć http://www.yiiframework.com/wiki/486/defaultscope/ - user2636556
Proszę wyjaśnić, jakie podmioty posiadasz? I dlaczego chcesz użyć modelu 1 AR dla 2 tabel db? - Aleksei Akireikin
Tabela @AlexAkr coz 1 zawiera informacje o nowych produktach i 1 użył. Wiem, że mogę po prostu scalić je obie w jedną tabelę i oznaczyć je jako nowe i używane. (co byłoby prostsze), niestety 2 tabele są często aktualizowane i są nam przekazywane na kilka tygodni na CD. Chciałbym po prostu zaktualizować mysql tak jak jest - user2636556
hi @ user2636556, jeśli powiesz mi, czego mi brakuje w mojej odpowiedzi, mogę to naprawić lub zakończyć pomaganie ci z tym, naprawdę myślę, że odpowiedź na to pytanie jest tutaj, pozdrowienia - DiegoCoderPlus
@DiegoCoderPlus nie całkiem dostaję to, co próbujesz zrobić :( chcę tylko sposób, gdzie, jeśli to zrobię Abc::model()->findAll() Otrzymuję wyniki obu tabel unioned razem - user2636556


Odpowiedzi:


Możesz użyć Yii konstruktor zapytań; Jest to rozwiązanie typu "go-to", gdy trzeba budować niestandardowe zapytania, a także obsługuje on natywnie UNION:

$data = Yii::app()->db->createCommand()
  ->select('*')
  ->from('abc')
  ->union('SELECT * FROM `abc2`')
  ->where('make_code=:make_code', [':make_code'=>42])
  ->queryAll();

Zamiast tego możesz użyć bezpośredniego zapytania ->getText() lub napisz ręcznie SQL, a następnie wykorzystaj CSqlDataProvider aby utworzyć konfigurowalne źródło danych.


3
2018-01-17 21:01



więc nie ma sposobu, aby go użyć defaultScope()? Za każdym razem, gdy nazywam ten model abc muszę mieć niestandardową funkcję, która wykonuje połączenie i nazywa to? - user2636556
@ user2636556: Nie ma mowy. defaultScope jest zasilany CDbCriteriai możesz zobaczyć w dokumentach, że klasa nie ma żadnego przepisu na wsparcie selekcji związków. - Jon


Witam mam nadzieję, że mogę ci pomóc, teraz cdbcriteria yii 1.x nie jest gotowy na związki ... więc myślę więcej o innych rozwiązaniach lub wa.

więc prosty sposób obejścia tego jest utworzenie widoku z kwerendy, które potrzebujesz, która jest:

CREATE VIEW unionAbc AS
SELECT * FROM `abc` 
UNION ALL 
SELECT * FROM `abc2`

następnie z tego widoku możesz zbudować nowy model i nazwać go bez większego wysiłku.

inne rozwiązanie, które znalazłem, to połączenie wyników zapytań modelu, to mówię ci z punktu widzenia teorii php, co mam na myśli to, że kiedy generujesz zapytanie modelowe w yii, to powracasz i tablicę lub obiekt, będziesz potrzebować używać konwerterów tablicowych z modelu istniejącego w programie yii helper, a następnie scalać obydwie tablice, co spowoduje powstanie nowego z obu informacjami

trzecim rozwiązaniem, które nie zostało przetestowane, byłoby:

$dataProvider =  new CArrayDataProvider('User');
$dataProvider->setData($modelabc->findAll());
$dataProvider->setData($modelabc2->findAll());

pozdrowienia.


2
2018-01-16 20:02



więc za każdym razem mam aktualizację abc lub abc2 tabele muszę przejść do phpmyadmin i utworzyć widok unionAbc ? - user2636556
wcale nie, widok jest tworzony tylko raz, a potem zachowuje się po kwerendzie wprowadzonym w jego tworzeniu ... - DiegoCoderPlus


proponuję rozwiązanie KISS:
czy możliwe jest tworzenie widoku z wyboru związków i praca z nim?
a następnie utworzyć aktywny rekord z tego widoku.
 oczywiście dla tworzenia / usuwania danych w interfejsie użytkownika, musisz utworzyć model osobno w obu tabelach.
 
Aktualizacja
możesz utworzyć widok w bazie danych: CREATE VIEW abc_union AS SELECT * FROM abc UNION ALL SELECT * FROM abc2 
a następnie wygeneruj model z Gii dla tego widoku.


2
2018-01-19 11:01



dowolny przykładowy kod? nie do końca rozumiem - user2636556
zaktualizuj moją odpowiedź ... - Amini


Po pierwsze, jeśli masz dwie równe tabele w DB, być może lepiej będzie je zebrać w jeden. Realizacja YY's ActiveRecord w oparciu o prostą regułę: jedna tabela -> jeden aktywny model rekordu.

Proponuję ci to rozwiązanie używając wzorca repozytorium. Nie sądzę, że korzystanie z defaultScope() jest niezbędna.

1. Stwórz interfejs, aby zapewnić, że oba modele produktów wdrażają niektóre popularne metody.

interface Product
{
    public function findAllByMakeCode($makeCode);

    // other common methods here
}

2. Stwórz cechę za pomocą typowych implementacji metod lub domyślnego zakresu, którego potrzebujesz.

trait ProductTrait
{
    function findAllByMakeCode($makeCode)
    {
        return $this->model()->findAllByAttributes(['make_code' => $makeCode]);
    }

    function defaultScope()
    {
        // your default scope condition
        // for example field is_deleted equals to 0
        return ['condition' => 'is_deleted=0'];
    }
    // other common methods implementation
}

3. Utwórz oddzielne modele AR dla obu tabel.

// used product entity
class ProductUsed extends CActiveRecord implements Product
{
    use ProductTrait;

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    public function tableName()
    {
        return 'product_used';
    }
}

// new product entity
class ProductNew extends CActiveRecord implements Product
{
    use ProductTrait;

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    public function tableName()
    {
        return 'product_new';
    }
}

4. Utwórz klasę repozytorium.

class ProductRepository
{   
    public function findAllByMakeCode($makeCode)
    {
        return array_merge(
            ProductUsed::model()->findAllByMakeCode($makeCode),
            ProductNew::model()->findAllByMakeCode($makeCode)
        );
    }

    public function findAll($condition = '', array $params = [])
    {
        return array_merge(
            ProductUsed::model()->findAll($condition = '', array $params = []),
            ProductNew::model()->findAll($condition = '', array $params = [])
        );
    }
}

5. Użyj go.

$repository = new ProductRepository();

// all products
$products = $repository->findAll();

// products with 42 make code
$products42 = $repository->findAllByMakeCode(42);

Może to trochę skomplikowane, ale warto.


1
2018-01-18 10:46



$makeCode to warunek, który dodam później "gdy jest potrzebny", a nie część defaultScope() czy nadal można to zrobić? - user2636556
Oczywiście, możesz dodać domyślny zakres dla obu modeli w ProductTrait. Odpowiedź została zaktualizowana. Nawiasem mówiąc, głównym celem domyślnego zakresu jest filtrowanie wierszy tabeli według niektórych warunków (np. is_deleted flaga nierozstrzygnięta) nie dla union, joinitp. - Aleksei Akireikin


Możesz zrobić UNIA lubię to;

$firtQuery = Yii::app()->db->createCommand()
    ->select("*")
    ->from('abc')
    //->where() you can add WHERE clause in here
    ->getText();

$result = Yii::app()->db->createCommand()
    ->select("*")
    ->from('abc2')
    //->where() you can add WHERE clause in here
    ->union($firtQuery)
    ->queryRow();

1
2018-01-24 04:10



w jaki sposób uczyniłbym go domyślnym zapytaniem dla modelu? więc w każdej chwili $a=new Abc; nazywa się, to już związek? - user2636556