質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

Python: JSONデータを一括でSQLServerのあるテーブルにINSERTしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 358

saya24

score 124

色々文献をあさっているのですが、こちらの記事を見た限り For文が登場していることから JSONデータのレコードの分 INSERT文を発行しなければならないような作りなのかな?と思いました。

Pythonが稼働する筐体と、DBサーバの筐体は別であり、レコード数に左右してこの筐体間のトラフィックが発生するのは最良ではないような気がしました。

一回のSQL文の発行で、JSONデータを取り込む方法があれば 教えてください。
こちらのMSの記事を見たのですが、今度はDBMS側に特化した記事になっており、Python内で生成されるJSONデータを どうDBMSに適用すれば良いのだろう(ファイルとして保存されていない)、と悩んでいます。

参考になる記事のご紹介でも結構です、ご見解をよろしくお願いします。


14:25追記

def jsonINSERT(_cn, _cur, jdata):
    SQL = """
        INSERT INTO TSTTBL VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    """
    _cur.executemany(SQL, jdata)
    _cn.commit()
    return


取込もうとしているJSONデータ
JSON

上記executemanyメソッド部分から発せられているだろうエラー

'The SQL contains 56 parameter markers, but 1 parameters were supplied', 'HY000'

2020/03/03 19:26追記
columns = tuple(fetch_dat[0].keys()) の行で 'str' object has no attribute 'keys' となります...
編集後の実行状況

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yoorwm

    2020/02/27 10:25

    JSON文字列をそのままINSERTという方法もあるので、そのJSONデータを「どのように使用するのか?」という所を考えて質問すると良いかもしれません。
    (ユーザIDだけ拾って、ユーザIDとデータだけのレコードでもいい場合がありますし。)

    キャンセル

  • saya24

    2020/02/27 14:24

    yoorwmさん
    SQLServer上のテーブルは 既に業務で運用されているもので、辞書形式の内容は各列に収まる必要があります。現在のステータスを本文に追加します。executemanyメソッドを実行するとエラーが現れています。

    キャンセル

回答 1

checkベストアンサー

0

sqliteでのコード例を示します。ポイントは

  • jsonデータ(に含まれている列名)から動的にSQLクエリ文字列を作成
  • jsonデータからexecutemanyに渡すべき値をタプルにしたリストを作成

です。

import sqlite3
import json

# テストテーブルを作成
con = sqlite3.connect('test.db')
cur = con.cursor()
cur.execute('drop table if exists t_test;')
cur.execute('create table if not exists t_test(num int, str text);')
cur.executemany("insert into t_test(num, str) values(?,?)",[(1,'a'),(2,'b')])
con.commit()
con.close()

# テストデータ。fetchallなりで取り出してきたもの
fetch_dat = [('{"num": 3, "str": "c"}',), ('{"num": 4, "str": "d"}',)]

# タプルで包まれているので、包みを取り除く
fetch_dat = [json.loads(t[0]) for t in fetch_dat]
print(fetch_dat) # [{'num': 3, 'str': 'c'}, {'num': 4, 'str': 'd'}]

# クエリ文字列を作成
columns = tuple(fetch_dat[0].keys())
params = ['?' for _ in range(len(columns))]
sql = 'insert into t_test({}) values({})'.format(','.join(columns), ','.join(params))
print(sql) # insert into t_test(num,str) values(?,?)

# クエリに渡すデータ。値をタプルにしたリスト
datas = [tuple(e.values()) for e in fetch_dat]

# テーブルに複数レコード追加
con = sqlite3.connect('test.db')
cur = con.cursor()
cur.executemany("insert into t_test(num, str) values(?,?)",datas)
con.commit()
con.close()

# 確認表示
con = sqlite3.connect('test.db')
cur = con.cursor()
cur.execute("select * from t_test;")
rows = cur.fetchall()
for row in rows:
    print( row)
con.close()
#(1, 'a')
#(2, 'b')
#(3, 'c')
#(4, 'd')

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/04 07:35

    ご見解をありがとうございます。今は環境が手元になく、発生したエラーメッセージを貼り付けられないのですが、後ほど貼り付けようと思います、すみません。

    確かに利用のDBMS•ドライバに依存する部分かも知れませんね。変更設定出来ると良いのですが。

    エラーメッセージでググれば 解決できるかな。

    ではまた後ほど

    キャンセル

  • 2020/03/04 08:34 編集

    fetch_dat = [json.loads(t[0]) for t in fetch_dat]
    の部分で、
    「Expecting value: line 1 column 1244 (char 1243)」
    というエラーメッセージが出ていることを確認しました。DBMS云々のはなしではないようでした、妙なことを言ってすみません。

    これからググってみますが、現段階で検討がつきません

    キャンセル

  • 2020/03/04 13:03

    fetch_dat = [json.loads(t[0]) for t in fetch_dat] のステップで得られるリスト内の辞書ですが、
    keyと値の括りをシングルクォートからダブルクォートへ 変更することはできますか?

    現在fetch_datのprint結果は [{'ITEMCODE': 'A001234', 'DISPLAYREVISIONNO': 1, 'ITEMNAME': 'ABCDEFGHIJKL', 'ITEMNAME_ID': '~0000PCJSU',....................................
    となっています。
    http://nekoyukimmm.hatenablog.com/entry/2016/07/14/213140
    の記事に その事象を要因に記載されているのですが、別データベースから取得するデータ群の中に意図せずシングルクォートが含まれているのでは?? と疑いだしています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる