【问题标题】:Print results in MySQL format with Python使用 Python 以 MySQL 格式打印结果
【发布时间】:2021-09-15 00:44:30
【问题描述】:

以与 MySQL 在控制台中使用 Python 打印结果相同的方式打印 MySQL 查询结果的最简单方法是什么?例如,我想得到类似的东西:

+---------------------+-----------+---------+
| font                | documents | domains |
+---------------------+-----------+---------+
| arial               |     99854 |    5741 |
| georgia             |     52388 |    1955 |
| verdana             |     43219 |    2388 |
| helvetica neue      |     22179 |    1019 |
| helvetica           |     16753 |    1036 |
| lucida grande       |     15431 |     641 |
| tahoma              |     10038 |     594 |
| trebuchet ms        |      8868 |     417 |
| palatino            |      5794 |     177 |
| lucida sans unicode |      3525 |     116 |
| sans-serif          |      2947 |     216 |
| times new roman     |      2554 |     161 |
| proxima-nova        |      2076 |      36 |
| droid sans          |      1773 |      78 |
| calibri             |      1735 |      64 |
| open sans           |      1479 |      60 |
| segoe ui            |      1273 |      57 |
+---------------------+-----------+---------+
17 rows in set (19.43 sec)

注意:我不知道每列的最大宽度是先验的,但我希望能够做到这一点而无需翻阅表格两次。我应该为每列添加查询长度()吗? MySQL 如何做到这一点,以免严重影响内存或处理时间?

编辑

我认为这与问题无关,但这是我发送的查询:

SELECT font.font as font,count(textfont.textid) as documents, count(DISTINCT td.domain) as domains
FROM textfont 
RIGHT JOIN font
ON textfont.fontid = font.fontid
RIGHT JOIN (
        SELECT text.text as text,url.domain as domain, text.textid as textid 
        FROM text 
        RIGHT JOIN url 
        ON text.texturl = url.urlid) as td 
ON textfont.textid = td.textid
WHERE textfont.fontpriority <= 0 
AND textfont.textlen > 100
GROUP BY font.font 
HAVING documents >= 1000 AND domains >= 10
ORDER BY 2 DESC;

这是我使用的python代码:

import MySQLdb as mdb

print "%s\t\t\t%s\t\t%s" % ("font","documents","domains")
res = cur.execute(query , (font_priority,text_len,min_texts,min_domains))
for res in cur.fetchall():
    print "%s\t\t\t%d\t\t%d" % (res[0],res[1],res[2])

但是由于宽度不同,这段代码会产生混乱的输出。

【问题讨论】:

  • 您能否为我们提供一些示例输入以用于您显示的输出?
  • 您使用什么 Python 模块与数据库交互?它是否符合 Python 数据库 API v2.0(PEP 249?)?即它是否将查询结果作为列表返回?
  • @Ben 我使用MySQLdb,我使用cursor 执行查询,然后使用fetchall(我相信它是一个生成器)。每个结果项都是一个元组。
  • str.ljust 可能就是你要找的东西

标签: python mysql


【解决方案1】:

不需要外部库。打印出带有列名的数据。如果您不需要列名,则可以删除所有带有“列”变量的行。

sql = "SELECT * FROM someTable"
cursor.execute(sql)
conn.commit()
results = cursor.fetchall()

widths = []
columns = []
tavnit = '|'
separator = '+' 

for cd in cursor.description:
    widths.append(max(cd[2], len(cd[0])))
    columns.append(cd[0])

for w in widths:
    tavnit += " %-"+"%ss |" % (w,)
    separator += '-'*w + '--+'

print(separator)
print(tavnit % tuple(columns))
print(separator)
for row in results:
    print(tavnit % row)
print(separator)

这是输出:

+--------+---------+---------------+------------+------------+
| ip_log | user_id | type_id       | ip_address | time_stamp |
+--------+---------+---------------+------------+------------+
| 227    | 1       | session_login | 10.0.0.2   | 1358760386 |
| 140    | 1       | session_login | 10.0.0.2   | 1358321825 |
| 98     | 1       | session_login | 10.0.0.2   | 1358157588 |
+--------+---------+---------------+------------+------------+

神奇之处在于每行cursor.description 的第三列(在代码中称为cd[2])。此列表示最长值的字符长度。因此,我们将显示列的大小设置为与列标题本身的长度之间的较大值 (max(cd[2], len(cd[0])))。

【讨论】:

  • 有两件事可以帮助尝试使用 psycopg 的人:首先,cd[2] 的值通常不会使用 psycopg 设置,因此要获得列的最大长度,您可以执行类似 @987654327 的操作@ 然后是max(max_col_length, len(cd[0]))。其次,如果您想截断列文本的长度以及填充它,您可以将tavnit += " %-"+"%ss |" % (w,) 替换为tavnit += " %-"+"%s.%ss |" % (w,w)
【解决方案2】:

使用prettytable

x = PrettyTable(["City name", "Area", "Population", "Annual Rainfall"])
x.set_field_align("City name", "l") # Left align city names
x.set_padding_width(1) # One space between column edges and contents (default)
x.add_row(["Adelaide",1295, 1158259, 600.5])
x.add_row(["Brisbane",5905, 1857594, 1146.4])
x.add_row(["Darwin", 112, 120900, 1714.7])
x.add_row(["Hobart", 1357, 205556, 619.5])
x.add_row(["Sydney", 2058, 4336374, 1214.8])
x.add_row(["Melbourne", 1566, 3806092, 646.9])
x.add_row(["Perth", 5386, 1554769, 869.4])
print x

+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
| Adelaide  | 1295 |  1158259   |      600.5      |
| Brisbane  | 5905 |  1857594   |      1146.4     |
| Darwin    | 112  |   120900   |      1714.7     |
| Hobart    | 1357 |   205556   |      619.5      |
| Sydney    | 2058 |  4336374   |      1214.8     |
| Melbourne | 1566 |  3806092   |      646.9      |
| Perth     | 5386 |  1554769   |      869.4      |
+-----------+------+------------+-----------------+

【讨论】:

  • 不知道这个第 3 方库 .. 谢谢 .. 看起来很有用。
【解决方案3】:

使用 Python 库tabulate 将 MySQL 结果打印成 MySQL 表格式的最佳和最简单的方法

user@system$ pip install tabulate

Python 代码:

import mysql.connector
from tabulate import tabulate

mydb = mysql.connector.connect(
                host="localhost",
                user="root",
                passwd="password",
                database="testDB"
              )

mycursor = mydb.cursor()
mycursor.execute("SELECT emp_name, salary FROM emp_table")
myresult = mycursor.fetchall()


print(tabulate(myresult, headers=['EmpName', 'EmpSalary'], tablefmt='psql'))

输出:

user@system:~$ python python_mysql.py
+------------+-------------+
| EmpName    | EmpSalary   |
|------------+-------------|
| Ram        | 400         |
| Dipankar   | 100         |
| Santhosh   | 200         |
| Nirmal     | 470         |
| Santu      | 340         |
| Shiva      | 100         |
| Karthik    | 500         |
+------------+-------------+

【讨论】:

  • 获取所有像这样的字段名称 field_names = [i[0] for i in mycursor.description] print(tabulate(myresult, headers=field_names, tablefmt='psql'))
【解决方案4】:

你需要做两遍:

  1. 计算列宽
  2. 打印表格

所以

table = cur.fetchall()
widths = [0]*len(table[0])  # Assuming there is always one row
for row in table:
    widths = [max(w,len(c)) for w,c in zip(widths,row)]

现在你可以简单地打印表格了。

在打印数字时记住string.rjust 方法。

更新

计算widths 的更实用的方法是:

sizetable = [map(len,row) for row in table]
widths = map(max, zip(*sizetable))

【讨论】:

    【解决方案5】:

    数据似乎在某个列表中,并且正在打印标题。考虑一些这样的格式:

    res = ['trebuchet ms', 8868, 417]
    res = ['lucida sans unicode', 3525, 116]
    

    print(' {0[0]:20s} {0[1]:10d} {0[2]:10d}'.format(res))
    

    给你

     trebuchet ms               8868        417
     lucida sans unicode        3525        116
    

    注意列表的索引是在字符串内部完成的,format 只需要提供列表或元组。

    或者,您可以通过编程方式指定宽度:

    wid1 = 20
    wid2 = 10
    wid3 = 10
    print(' {:{}s} {:{}d} {:{}d}'.format(res[0], wid1, res[1], wid2, res[2], wid3))
    

    提供与上述相同的输出。

    您必须根据需要调整字段宽度并循环遍历每行数据的列表,而不是组成示例行。数字自动右对齐,字符串自动左对齐。

    对某些人来说,优势当然是它不依赖任何外部库,而是使用 Python 已经提供的功能。

    了解更多关于字符串格式化here

    【讨论】:

      【解决方案6】:

      我修改了dotancohen's answer,所以只需要字典的结果列表作为输入。如果您已经有一个返回结果的库方法,这很有用:

      def format_table(self, results:list):
          if not len(results):
              return []
          widths = []
          max_widths = {}
          tavnit = '|'
          separator = '+'
          report = []
          # add col headers length to widths
          for key in results[0].keys():
              max_widths[key] = len(key)
          # add max content lengths to widths
          for row in results:
              for key in row.keys():
                  if len(str(row[key])) > max_widths[key]:
                      max_widths[key] = len(str(row[key]))
          for key in results[0].keys():
              widths.append(max_widths[key])
          for w in widths:
              tavnit += " %-" + "%s.%ss |" % (w, w)
              separator += '-' * w + '--+'
          # build report
          report.append(separator)
          report.append(tavnit % tuple(results[0].keys()))
          report.append(separator)
          for row in results:
              report.append(tavnit % tuple(row.values()))
          report.append(separator)
          return report
      

      【讨论】:

        猜你喜欢
        • 2022-08-06
        • 2014-11-08
        • 2020-07-15
        • 1970-01-01
        • 2016-05-26
        • 2012-06-04
        • 1970-01-01
        • 2017-03-10
        • 1970-01-01
        相关资源
        最近更新 更多