2016-06-16 9 views
0

私は私の-SQLクライアントで次のSQLを実行し、正しい結果を返すことができます。私のPythonコードでmysql文を実行するには?

mysql> select cj.name job_name , cb.build_result build_result, count(*) total , GROUP_CONCAT(cb.id) id_list 
     from ci_build as cb INNER JOIN ci_job as cj 
     ON cb.job_id = cj.id 
     where cb.build_time > date_format('2016-04-16','%Y%m%d') 
     and cb.build_time < date_format('2016-05-27','%Y%m%d') 
     GROUP BY cj.name , cb.build_result; 

enter image description here

をしかし、私は次のPythonコードを使用する場合、それはエラーを返します。

とValueError:サポートされていない形式の文字 'Y'(0x59)インデックス225

でいずれかが私のPythonコードと間違って何を助けることができますか?多くのおかげであなたはほかに%オペレータのargumewntsといくつかの点で補間したくないパーセント記号を倍増しなければならない〜

start_time = '2016-04-16' 
end_time = '2016-05-27' 

db = MySQLdb.connect(host='xxxx',port=3306,user='xxxx', passwd='xxxx', db='xxxx',charset='utf8') 

sql_query = "select cj.name job_name , cb.build_result build_result, count(*) total , GROUP_CONCAT(cb.id) id_list from ci_build as cb INNER JOIN ci_job as cj ON cb.job_id = cj.id where cb.build_time > date_format(%s,'%Y%m%d') and cb.build_time < date_format(%s,'%Y%m%d') GROUP BY cj.name , cb.build_result; % (start_time , end_time) 

cursor = db.cursor() 
cursor.execute(sql_query) 
all_res=cursor.fetchall() 
cursor.close() 
db.close() 
+2

質問には「閉じる」がありません。最初に修正することはできますか? –

答えて

2

2つのdate_format()%sを、しかし、%は文字列補間の特殊文字であるため、%Yも文字列の書式設定操作であるとPythonは考えていますが、Yは有効な書式指定子ではありません。

あなたのクエリ文字列に%を倍にすることによって、他の%文字をエスケープすることができます

date_format('%s','%%Y%%m%%d') 

はまた、あなたが文字列を送信しているので、%sを引用する必要があります。

しかし、私はこれが可能SQLインジェクションの脆弱性を回避するのに役立つよう、あなたが代わりにパラメータ化クエリを使用することをお勧めします:

sql_query = "select cj.name job_name , cb.build_result build_result, count(*) total , GROUP_CONCAT(cb.id) id_list from ci_build as cb INNER JOIN ci_job as cj ON cb.job_id = cj.id where cb.build_time > date_format(%s,'%%Y%%m%%d') and cb.build_time < date_format(%s,'%%Y%%m%%d') GROUP BY cj.name , cb.build_result" 

cursor = db.cursor() 
cursor.execute(sql_query, (start_time , end_time)) 

これはcursor.execute()に渡され、別のタプルのクエリに引数をsuplies。データベースエンジンは、引用符やその他の特殊文字が適切にエスケープされていることを確認して、置換を安全に実行します。プレースホルダ(%s)をここで引用してはいけません。エンジンがそれを行います。

+0

あなたの親切に助けてくれてありがとう詳細な説明、多くを学んだ:) – JiangLing

0

;-)

sql_query = "select cj.name job_name , cb.build_result build_result, count(*) total , GROUP_CONCAT(cb.id) id_list from ci_build as cb INNER JOIN ci_job as cj ON cb.job_id = cj.id where cb.build_time > date_format('%s','%%Y%%m%%d') and cb.build_time < date_format('%s','%%Y%%m%%d') GROUP BY cj.name , cb.build_result;" % ('a', 'b') 

は動作します。文字列リテラル'a', 'b'を使用して申し訳ありません。もちろん、変数を入力する必要があります。

また(@MosesKoledoyeが述べたように)文字列を終了するには、セミコロンの後に追加閉じる二重引用符に注意して、データベースが文字列で埋め受信したときには、「挿入リテラル開始と終了をラップする'%%s'を追加するために、多分良いでしょう(これは@sparkandshineと二重引用符ではありません)。

@mhawke注:変数からのものを注入してSQLクエリ文字列を作成しないようにしてください!

いつかはあなたのコンテンツを制御して、翌日にコードをリファクタリングし、 "外部から"変数を受け取ると、SQLインジェクションは準備が整いました。既にPREPARE段階で最適化を行い、EXECUTEフェーズ時にBINDフェーズで注入を拒否して自動的に階層化されたセキュリティを追加することが可能です

+0

おかげで、この問題は長い間悩まされています。今、理解が深まりました。ありがとうございます。 – JiangLing

関連する問題