59

I have two databases, and every database has the same table with the same fields, but how do I get all records from all of two databases at the same time in Yii 2.0?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Chhorn Soro
  • 2,735
  • 5
  • 22
  • 41

4 Answers4

117

First you need to configure your databases like below:

return [
'components' => [
    'db1' => [
        'class' => 'yii\db\Connection',
        'dsn' => 'mysql:host=localhost;dbname=db1name', //maybe other dbms such as psql,...
        'username' => 'db1username',
        'password' => 'db1password',
    ],
    'db2' => [
        'class' => 'yii\db\Connection',
        'dsn' => 'mysql:host=localhost;dbname=db2name', // Maybe other DBMS such as psql (PostgreSQL),...
        'username' => 'db2username',
        'password' => 'db2password',
    ],
],
];

Then you can simply:

// To get from db1
Yii::$app->db1->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()

// To get from db2
Yii::$app->db2->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()

If you are using an active record model, in your model you can define:

public static function getDb() {
    return Yii::$app->db1;
}

//Or db2
public static function getDb() {
    return Yii::$app->db2;
}

Then:

If you have set db1 in the getDb() method, the result will be fetched from db1 and so on.

ModelName::find()->select('*')->all();
gvlasov
  • 14,781
  • 17
  • 61
  • 99
Ali MasudianPour
  • 13,704
  • 3
  • 57
  • 61
  • 4
    Thanks in advance for your great answer.It's really helpful. – Chhorn Soro Dec 03 '14 at 14:12
  • 2
    I get an error by using your code. It's not completely wrong, but I think you missed something. You left out "'class' => 'yii\db\Connection'" after return [ – nodeffect May 26 '15 at 02:37
  • I'm having an error.... Under my models, I use "Yii::$app->db1->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll();" but I'm having this error "Getting unknown property: yii\web\Application::db1" – nodeffect May 26 '15 at 08:35
  • 1
    *Great One !!* Thumbs Up. – Nana Partykar Mar 14 '16 at 14:50
  • 1
    Am I the only one that have this method static in ActiveRecord and cant overwrite it with a non-static method? – pgarriga May 04 '16 at 15:36
  • Your Answer helped me... Thanks... How I can get database name from component? I need to use it in query string.. – Chaitanya May 20 '16 at 06:50
  • 2
    should be `public static function getDb()` use **static** because it is override static method. – bowpunya Oct 08 '17 at 06:07
  • What if i need data from second database using model query ? not createCommand. – TrickStar May 07 '20 at 13:14
21

Just to add: I followed the answer provided but still got an error: "Unknown component ID: db"

After some testing, here is what I discovered: The function getDB is only called AFTER a connection is made to db. Therefore, you cannot delete or rename 'db' in the config file. Instead, you need to let the call to 'db' proceed as normal and then override it afterwards.

The solution (for me) was as follows:

In config/web.php add your second database configuration below db as follows:

'db' => require(__DIR__ . '/db.php'),
'db2' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=name',
    'username' => 'user',
    'password' => 'password',
    'charset' => 'utf8',
    'on afterOpen' => function ($event) {
        $event->sender->createCommand("SET time_zone = '+00:00'")->execute();
    },
],

DO NOT rename db. Failure to find db will cause an error. You can name db2 whatever you like.

Now in the model, add the following code:

class ModelNameHere extends \yii\db\ActiveRecord {

   // add the function below:
   public static function getDb() {
       return Yii::$app->get('db2'); // second database
   }

This will now override the default db configuration.

I hope that helps somebody else.

Note: you can include the configuration for db2 in another file but you cannot include it in the db.php file (obviously). Instead, create a file called db2.php and call it as you do db:

'db' => require(__DIR__ . '/db.php'),    
'db2' => require(__DIR__ . '/db2.php'),

Thanks

Simon East
  • 46,575
  • 14
  • 130
  • 124
DrBorrow
  • 809
  • 8
  • 19
  • I renamed 'db' and it worked. Apart from that, your solution works. – ColinWa Sep 20 '16 at 19:23
  • I've tried yours, but I got `SQLSTATE[42000]: [Microsoft][ODBC Driver 11 for SQL Server][SQL Server]Incorrect syntax near '='. The SQL being executed was: SET time_zone = '+00:00'`, any idea? thanks – Blackjack Dec 04 '17 at 14:03
2

Our situation is a little more complex, we have a "parent" database which has a table that contains the name of one or more "child" databases. The reason for this is that the Yii project is instantiated for each of our clients, and the number of child databases depends on the client, also the database names are arbitrary (although following a pattern).

So we override \yii\db\ActiveRecord as follows:

class LodgeActiveRecord extends \yii\db\ActiveRecord
{

public static function getDb()
{
    $lodgedb = Yii::$app->params['lodgedb'];
    if(array_key_exists( $lodgedb, Yii::$app->params['dbs'])) {
        return Yii::$app->params['dbs'][ $lodgedb ];
    }
    $connection = new \yii\db\Connection([
        'dsn' => 'mysql:host=localhost;dbname=' . $lodgedb,
        'username' => Yii::$app->params['dbuser'],
        'password' => Yii::$app->params['dbpasswd'],
        'charset' => 'utf8',
    ]);
    $connection->open(); // not sure if this is necessary at this point
    Yii::$app->params['dbs'][ $lodgedb ] = $connection;
    return $connection;
}

}

Before calling any database function, first set Yii::$app->params['lodgedb'] to the name of the database required:

Yii::$app->params['lodgedb'] = $lodge->dbname; // used by LodgeActiveRecord

Your model classes don't change except they extend from LodgeActiveRecord:

class BookingRooms extends \app\models\LodgeActiveRecord

Nik Dow
  • 538
  • 4
  • 10
0

If you're using schmunk42/yii2-giiant to generate model classes, there is a 'modelDb' property which you can set to use a database component other than 'db'.

rob006
  • 18,710
  • 5
  • 41
  • 58
gvlasov
  • 14,781
  • 17
  • 61
  • 99