2017-01-14 11 views
0

現在のMySql DBサーバーでは、「Friends」、「Places」という2つのスキーマがあります。 DB全体は、外部から呼び出されているストアドプロシージャを中心に構成されています。多分それは良いアプローチです、多分それは悪いですが、私は持っているこの問題に関連していません。この場合、DBはそれを使用している外部のソフトウェアから分離する必要があります(私はDBを担当するだけです)。動的SQLの代替案(MySql)

"Friends"スキーマのストアドプロシージャの中には、 "Places"のテーブルとその逆もあります。さて、たとえば、私が同じサーバ上に、スキーマのセットアップ新しいセットをしたいが、このような別の「クライアント」のための場合:

Friends_clientOne 
Places_clientOne 
Friends_clientTwo 
Places_clientTwo 

私は問題を抱えていることは - 「別のスキーマウォンからテーブルを参照するストアドプロシージャをどのスキーマ名を使用するかを知っています。新しいセットが作成されるたびに、適切なスキーマ名をスイートに設定するために、各プロシージャおよび各プロシージャを確認および変更することはオプションではありません。動的SQLはまったく新しいものです。それ以外のオプションは何ですか?私は、例えば、これを行うことができます方法:

(stored procedure inside schema Friends_clientOne): 
Select * from Places_<getCurrentSchemaSuffix>.someTable; 

これはPerconaについてどう:(ためにMySQLが十分に柔軟である私に教えてください

+0

のMicrosoft SQL Serverに関連する 'SQL-server'タグとまでは何もしていますMySQLでやります。 – tadman

+0

この種の問題は、悪い設計の兆候です – Strawberry

+0

It's MySql、edited – guest86

答えて

2

最も近いものを、組み込み関数DATABASE()で何を記述していますか?現在デフォルトデータベースを返します(http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_database)、。

デフォルトのデータベースは、必ずしも特定のテーブルが属するものではない。それは最も最近USE <databasename>文で指定されたデータベースです。あなたが頼ることができる場合常にdを使用するアプリケーションそのテーブルが属していることを意味するatabaseは、その関数を使用できます。

ただし、SQLの実装では、クエリの実行中に動的にテーブル名を変更することはできません。ステートメントの準備を行い、クエリにハードコーディングする場合は、の前にテーブルを指定することができます。テーブル名を変数にするための構文はありません。

DATABASE()機能を使用する場合でも、動的SQLを使用する必要があります。

Percona Serverは、この問題のOracle Oracle MySQLと違いはありません。

この問題のためのあなたのオプションは以下のとおりです。クライアントごとに複数のスキーマを使用して

  1. ストップ。各クライアントのすべてのデータを単一のスキーマに入れます。これは最も単純なようです。

  2. 各クライアントに固有のストアドプロシージャを設計します。あなたはこれをしたくないと言った。しかし、それは価値があるため、私は現在の仕事で管理する顧客データベースのストアドプロシージャとトリガでこれを行います。それは悪いことではありません。各トリガーまたはプロシージャーには、顧客IDのプレースホルダー・トークンを使用して、CREATEステートメントの「テンプレート」バージョンがあります。新しい顧客のデータベースを作成するときには、そのテンプレートコードをコピーして顧客IDのプレースホルダに置き換えて実行します。

  3. 各クライアントのデータを独自のMySQL Serverインスタンスに入れます。この方法では、クライアントごとに複数のスキーマを持つことができますが、スキーマ名は各クライアントごとに異なる必要はありません。 1つのサーバーホスト上で複数のインスタンスを実行できます。別々のdatadir、port、sock_file、およびその他のログファイルで構成するだけで済みます。このソリューションが使用されているのを見たことがありますが、リソースオーバーヘッドが多く、管理が難しいため、推奨しません。

  4. 動的SQLの使い方を学んでください。

1

あなたは、このような手続きオブジェクトでプリペアドステートメントを使用することができます。

DELIMITER // 

CREATE PROCEDURE getPlace (OUT param1 char) 
BEGIN 
    SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO @sql; 
    PREPARE getPlaces from @sql; 
    EXECUTE getPlaces; 
    DEALLOCATE PREPARE getPlaces; 
END; 
// 

DELIMITER ; 

サンプル

MariaDB [mysql]> CREATE DATABASE Friends_clientOne; 
Query OK, 1 row affected (0.00 sec) 

MariaDB [mysql]> CREATE DATABASE Friends_clientTwo; 
Query OK, 1 row affected (0.00 sec) 

MariaDB [mysql]> CREATE DATABASE Places_clientOne; 
Query OK, 1 row affected (0.00 sec) 

MariaDB [mysql]> CREATE DATABASE Places_clientTWO; 
Query OK, 1 row affected (0.00 sec) 

MariaDB [mysql]> CREATE TABLE Places_clientOne.someTable (name varchar(32)); 
Query OK, 0 rows affected (0.02 sec) 

MariaDB [mysql]> CREATE TABLE Places_clientTwo.someTable (name varchar(32)); 
Query OK, 0 rows affected (0.02 sec) 

MariaDB [mysql]> INSERT INTO Places_clientOne.someTable VALUES('text in Places_clientOne.someTable'); 
Query OK, 1 row affected, 1 warning (0.00 sec) 

MariaDB [mysql]> INSERT INTO Places_clientTwo.someTable VALUES('text in Places_clientTwo.someTable'); 
Query OK, 1 row affected, 1 warning (0.01 sec) 

MariaDB [mysql]> use Friends_clientOne; 
Database changed 
MariaDB [Friends_clientOne]> DELIMITER // 
MariaDB [Friends_clientOne]> CREATE PROCEDURE getPlace (OUT param1 char) 
    -> BEGIN 
    ->  SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO @sql; 
    ->  PREPARE getPlaces from @sql; 
    ->  EXECUTE getPlaces; 
    ->  DEALLOCATE PREPARE getPlaces; 
    -> END; 
    -> // 
Query OK, 0 rows affected (0.03 sec) 
MariaDB [Friends_clientOne]> DELIMITER ; 

MariaDB [(none)]> use Friends_clientTwo; 
Database changed 
MariaDB [Friends_clientTwo]> DELIMITER // 
MariaDB [Friends_clientTwo]> 
MariaDB [Friends_clientTwo]> CREATE PROCEDURE getPlace (OUT param1 char) 
    -> BEGIN 
    ->  SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO @sql; 
    ->  PREPARE getPlaces from @sql; 
    ->  EXECUTE getPlaces; 
    ->  DEALLOCATE PREPARE getPlaces; 
    -> END; 
    -> // 
Query OK, 0 rows affected (0.02 sec) 

MariaDB [Friends_clientTwo]> DELIMITER ; 
MariaDB [Friends_clientTwo]> call getPlace(@r); 
+----------------------------------+ 
| name        | 
+----------------------------------+ 
| text in Places_clientTwo.someTab | 
+----------------------------------+ 
1 row in set (0.00 sec) 

Query OK, 0 rows affected (0.00 sec) 

MariaDB [Friends_clientTwo]> use Friends_clientOne; 
Database changed 
MariaDB [Friends_clientOne]> call getPlace(@r); 
+----------------------------------+ 
| name        | 
+----------------------------------+ 
| text in Places_clientOne.someTab | 
+----------------------------------+ 
1 row in set (0.00 sec) 

Query OK, 0 rows affected (0.00 sec) 

MariaDB [Friends_clientOne]>