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

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

ただいまの
回答率

90.50%

  • Python

    8002questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • PostgreSQL

    1062questions

    PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

【Python】select結果をjosnファイルに出力したい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 324

s_akira

score 2

select結果を辞書型に出力する際の順番の指定方法について質問させていただきたいです。

下記のコード状態で、実行するとselect取得結果がテーブルカラムの順番とは違った形で出力されてしまいます。
selectで取得した結果(カラムの順番のまま)を、ファイルに出力したのですがどうしたらいいでしょうか。
※7行目の"dict"で順番が変更されてしまっていると思います。

コメントアウトした箇所を変更しましたら、順番がselectのとおりとなりました。(ありがとうございます。)
が、ファイル出力には、カラム名が出力されない状態です。

conn = psycopg2.connect(hostとかの設定)
cur = conn.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor)
#cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

cur.execute("SELECT カラム1, カラム2, カラム3, カラム4 from test")
#またはこっち
#cur.execute("SELECT * from test")
results = cur.fetchall()

dict_result = []
for row in results:
    dict_result.append(row._asdict())
    #dict_result.append(dict(row))

with open(filename, "w") as f:
        json.dump(results, f, indent=4)

以下のようなテーブルがあったとして、実行すると順番がカラム1〜4と順番の通りに出力さず順番がシャッフルされます。

カラム1 カラム2 カラム3 カラム4
A B C D

を上記コードで実行すると、以下のような感じでバラバラにされてしまいます。(ファイル出力時)

"カラム2": "B",
"カラム1": "A", 
"カラム4": "D",
"カラム3": "C"

printすると以下で表示されています。
[Record(column1='A         ', column2='B         ', column3='C         ', column4='D         ')]

これを、以下のようにテーブルのカラムの順番で表示させたいです。

”カラム1":"A",
”カラム2":"B",
”カラム3":"C",
"カラム4":"D"

検索をかけているのですがうまくいきません。以下、参考にしているURLです。
Pythonでリスト(配列)に要素を追加
Python psycopg2 で dict形式で結果を取得
Pythonで辞書を作成するdict()と波括弧、辞書内包表記

すみませんが、よろしくお願い致します。

〜備考〜
・言語:Python
・DB:postgresql
・Create文:
create table test (
column1 character(10)
,column2 character(10)
,column3 character(10)
,column4 character(10)
)
・insert文
insert INTO test (
column1,
column2,
column3,
column4
)
VALUES
(  'A',
'B',
'C',
'D'
)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • s_akira

    2018/06/24 23:20

    LouiS0616さん > 重要な箇所ミスしてしまいもうしわけありません。おっしゃるとおりです。

    キャンセル

  • umyu

    2018/06/24 23:56 編集

    今回の問題とは関係ありませんが、出力順を保証する必要があるのであればSELECT句にはORDER BY句を指定してくださいな。

    キャンセル

  • s_akira

    2018/06/25 11:39

    umyuさん > ご回答ありがとうございます、わかりました。

    キャンセル

回答 3

checkベストアンサー

+1

実は、Python3.5以下のdictは挿入した順番が維持されません。なので、順番を保持するにはcollentionsモジュールのOrderedDictを使う必要があります。
How to preserve column order while using psycopg2.extras.RealDictCursor
ここに詳しいですが、2行目cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)の代わりにpsycopg2.extras.NamedTupleCursorをつかって、7行目でdict_result.append(dict(row))dict_result.append(row._asdict())とすればよいかと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/25 01:19

    まだ、調査中なのですが。。解決できないため

    下記でエラーが出てしまいました・・・
    cur = conn.cursor(psycopg2.extras.NamedTupleCursor)

    TypeError: Expected bytes or unicode string, got type instead

    すみませんがなにかアドバイスありましたら教えていただけないでしょうか。

    キャンセル

  • 2018/06/25 01:26

    cur = conn.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor)

    に書き換えてみてください。

    キャンセル

  • 2018/06/25 01:55

    上記に変更して、実行しましたら、
    print(results)をするとほしい順番にでることができました!ありがとうございます!

    ファイル出力でカラムが出力されなくてうまくいっていませんのでもう少し調べてみます。

    キャンセル

  • 2018/06/25 07:50

    ファイル出力でカラムが出力されないとは、具体的にどういう状況なのでしょうか?

    キャンセル

  • 2018/06/25 11:09 編集

    何度も申し訳ありません。
    質問コードのファイル出力すると、下記のようになります。
    [
    [
    "A ",
    "B ",
    "C ",
    "D "
    ]
    ]
    が表示される状態です。A,B,C,Dの後ろに謎の空白もまざっており、確実に簡単なミスかとは思うのですが。。。
    print(results)をすると、[Record(column1='A ', column2='B ', column3='C ', column4='D ')]となっています。

    キャンセル

  • 2018/06/25 11:53

    frodo821さん
    何度もコメント申し訳ありません。

    json.dump(results, f, indent=4) が誤っておりました。
    正しくは、json.dump(dict_result, f, indent=4)でした。

    と修正したところほしい結果(以下)が出力されました。
    [
    {
    "column1": "A ",
    "column2": "B ",
    "column3": "C ",
    "column4": "D "
    }
    ]

    A,B,C,Dの後ろに謎の空白が入ってしまっていますが一旦出力できました。
    本当にありがとうございます。

    キャンセル

0

jsonモジュールのドキュメントを見なおしたら、もっとまともな解決法がありました。

書き出し時

json.dump(...)
sort_keys が true (デフォルトでは False です)であれば、辞書の出力がキーでソートされます。

import json

results = {
    "column2": "B",
    "column1": "A", 
    "column4": "D",
    "column3": "C"
}

with open('out.json', 'w') as f:
    json.dump(results, f, sort_keys=True)

読み出し時

json.load(...)
object_pairs_hook はオプションで渡す関数で、ペアの順序付きリストのデコード結果に対して呼ばれます。 object_pairs_hook の返り値は dict の代わりに使われます。この機能はキーと値のデコードされる順序に依存する独自のデコーダ (たとえば collections.OrderedDict() は挿入の順序を記憶します) を実装するのに使えます。

from collections import OrderedDict
import json

with open('out.json') as f:
    data = json.load(f, object_pairs_hook=OrderedDict)

print(data)

旧回答

SQLは触ったことがないので、見当違いなことを言っていたらすみません。


一般に辞書構造は順序を保証しませんので、二重リストとして出力するのが妥当かと。
追記: 書き出し時/読み出し時に充分な配慮があれば辞書構造でも良いようです。

オブジェクトは、順序付けされない名前/値のペアのセットです。
配列は、順序付けされた値の集まりです。

引用元: JSON の紹介

import json

results = {
    "column2": "B",
    "column1": "A", 
    "column4": "D",
    "column3": "C"
}

results_list = []
for key in sorted(results.keys()):
    results_list.append(
        [key, results[key]]
    )

# 内包表記を使う場合
# results_list = [[key, results[key]] for key in sorted(results.keys())]

print(results_list)  # [['column1', 'A'], ['column2', 'B'], ['column3', 'C'], ['column4', 'D']]

with open('out.json', 'w') as f:
    json.dump(results_list, f)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/25 11:41

    ご回答ありがとうございます。

    listのkey箇所で以下、エラーがでてしまう状態で。。。
    AttributeError: 'list' object has no attribute 'keys'

    もう少し調査していろいろしてみます!

    キャンセル

  • 2018/06/25 11:56 編集

    SQLでリスト形式でデータを受け取れるならそれに越したことはないです。

    ---
    私に分かるのは次の二点です。
    ・Pythonで一瞬でも組み込み辞書として扱うと順序は保証できない
    ・jsonにオブジェクト形式で出力しても順序は保証できない

    キャンセル

  • 2018/06/25 16:17

    LouiS0616さん
    承知いたしました。
    ご教示いただき、ありがとうございます!

    キャンセル

0

ソートしたい順に order by するだけで良いのでは?

cur.execute("SELECT カラム1, カラム2, カラム3, カラム4 from test")
                                                               ↓
cur.execute("SELECT カラム1, カラム2, カラム3, カラム4 from test order by カラム1, カラム2, カラム3, カラム4")

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/25 02:16

    ご回答ありがとうございます!

    order byをしただけですと、辞書型のせいかなぜか順番が制御できませんでした…

    キャンセル

  • 2018/06/25 02:20

    問題が速やかに解決できるように、質問にSQLで使っているテーブルのCREATE TABLE文も載せては?

    キャンセル

  • 2018/06/25 11:36

    追加してみました。ご指摘ありがとうございます。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る

  • Python

    8002questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • PostgreSQL

    1062questions

    PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。