2017-04-22 4 views
1

私は非常に遅いSQLサーバのどこから他の誰かによって管理された究極のデータソースを扱います。これに対処する私の前任者のソリューションは、クエリは、多かれ少なかれ似行うことです。外部データソースからのSQLテーブルの更新すべてのエントリを最初に削除することなく(ただし、削除されたエントリは削除しないでください)

results = python_wrapper('SELECT primary_key, col2, col3 FROM foreign_table;') 
other_python_wrapper('DELETE FROM local_table;') 
other_python_wrapper('INSERT INTO local_table VALUES() %s;' % results) 

問題は、これは、彼らが常にされているため、あなたが他のテーブルの外部キー制約などlocal_tableの値を使用しないことを意味しています削除し、外部ソースから更新するたびにテーブルに追加し直します。しかし、レコードが実際に結果の中の外注サーバーの問合せに消えた場合、外来キー制約とリンクしている他のローカル表のレコードを削除するカスケード・エフェクトをトリガーすることを意味します。外部表から伝播されたデータ。

のように、私が作ってみただけ半合理的な解決策は何かを行うことです。問題は、これらのテーブルのかなりの数がありますし、テーブルの多くは、列の数が多い

results = python_wrapper('SELECT primary_key, col2, col3 FROM foreign_table;') 
other_python_wrapper('DELETE FROM local_table_temp;') 
other_python_wrapper('INSERT INTO local_table_temp VALUES() %s;' % results) 
other_python_wrapper('DELETE FROM local_table WHERE primary_key NOT IN local_table_temp;') 
other_python_wrapper('INSERT INTO local_table SELECT * FROM local_table_temp ON DUPLICATE KEY UPDATE local_table.col2 = local_table_temp.col2, local_table.col3 = local_table_temp.col3 

更新する必要があるので、同じボイラープレートを&以上に書き込むのは面倒です。また、表のスキーマが変更された場合は、すべての列のリストを更新するために必要な複数の場所があります。

SQLコードでこれを行うための簡潔な方法はありますか?

ありがとうございます!

+0

あなたが見ています複製に? – Strawberry

+0

外国の低速なデータベースを、あまりアドホックな方法で複製することを意味するなら、それは私が考えていたものではありません。残念ながら、私のケースでは、それは多くの理由のための実用的な解決策ではないと思います: –

+0

1つは、外部データベースはOracleで、ローカルデータベースはMySQLです。ローカルでは、完全な外部SQLサーバーを複製するためのリソースがありません。また、Oracleデータベース・サーバーのライセンスを取得して実行することもできます。 –

答えて

0

私は自分自身の質問に対して幾分不満足な答えがあります。私はPythonを使用して外部のOracleデータベースを照会してSQLに入れています。テーブルとカラムの名前の形式はかなりうまくいくと信じていますので、手順全体をPythonコードで囲み、Pythonでテーブルの検査に基づいてSQL更新クエリを更新します。多くの理由から

、私はまだこれを行うには良い方法を見てみたいと思いますが、ので、それは私の作品:私は、データベースを調べることができ、外部のスクリプト言語を使用してい

  1. とにかくスキーマ。
  2. 私が作業しているデータベース、列、およびテーブル名は、私が直接制御できるすべてのものなので、正常に動作すると信じています。
  3. 私の解決方法は、ローカルのSQLテーブル構造によって異なります。具体的にどのキーが主キーであるかを示す。適切に構造化されたテーブルがなければ、コードは機能しません。しかし、これは問題ありません。私はPythonコードを動作させるためにMySQLテーブルを再構成することができるからです。

他の誰かがより洗練された汎用ソリューションを考えてもいいと思っていますが、同じ問題を抱えている人に自分のPythonコードを提供します私が上記で行った仮定。以下は

私はPythonで簡単なSQLクエリを実行するために使用するのpythonラッパーです:

import config, MySQLdb 
class SimpleSQLConn(SimpleConn):                   
    '''simplified wrapper around a MySQLdb.connection'''             

    def __init__(self, **kwargs):                   
     self._connection = MySQLdb.connect(host=config.mysql_host,          
              user=config.mysql_user,          
              passwd=config.mysql_pass,          
              **kwargs)              
     self._cursor = self._connection.cursor()               

    def query(self, query_str):                   
     self._cursor.execute(query_str)                 
     self._connection.commit()                   
     return self._cursor.fetchall() 

    def columns(self, database, table):                 
     return [x[0] for x in self.query('DESCRIBE `%s`.`%s`' % (database, table))g]      

    def primary_keys(self, database, table):                
     return [x[0] for x in self.query('DESCRIBE `%s`.`%s`' % (database, table)) if 'PRI' in x] 

そしてここでは、実際の更新機能である、上記のSQLラッパークラスを使用して:

def update_table(database, 
       table, 
       mysql_insert_with_dbtable_placeholder):                    
    '''update a mysql table without first deleting all the old records                 

    mysql_insert_with_dbtable_placeholder should be set to a string with                
    placeholders for database and table, something like:                    

    mysql_insert_with_dbtable_placeholder = "                       
    INSERT INTO `%(database)s`.`%(table)s` VALUES (a, b, c);               

    note: code as is will update all the non-primary keys, structure                 
    your tables accordingly                            
    '''                                 
    sql = SimpleSQLConn()                            
    query ='DROP TABLE IF EXISTS `%(database)s`.`%(table)s_temp_for_update`' %\               
     {'database': database, 'table': table}                       
    sql.query(query)                             
    query ='CREATE TABLE `%(database)s`.`%(table)s_temp_for_update` LIKE `%(database)s`.`%(table)s`'%\         
     {'database': database, 'table': table}                       
    sql.query(query)                             
    query = mysql_insert_with_dbtable_placeholder %\                     
     {'database': database, 'table': '%s_temp_for_update' % table}                 
    sql.query(query)                             
    query = '''DELETE FROM `%(database)s`.`%(table)s` WHERE                    
     (%(primary_keys)s) NOT IN                          
     (SELECT %(primary_keys)s FROM `%(database)s`.`%(table)s_temp_for_update`);              
     ''' % {'database': database,                          
       'table': table,                           
       'primary_keys': ', '.join(['`%s`' % key for key in sql.primary_keys(database, table)])}         

    sql.query(query)                             
    update_columns = [col for col in sql.columns(database, table)                  
         if col not in sql.primary_keys(database, table)]                 
    query = '''INSERT into `%(database)s`.`%(table)s`                     
    SELECT * FROM `%(database)s`.`%(table)s_temp_for_update`                   
    ON DUPLICATE KEY UPDATE                            
    %(update_cols)s                              
    ''' % {'database': database,                          
      'table': table,                            
      'update_cols' : ',\n'.join(['`%(table)s`.`%(col)s` = `%(table)s_temp_for_update`.`%(col)s`' \        
             % {'table': table, 'col': col} for col in update_columns])}          
    sql.query(query) 
関連する問題