今天有人问我 MySQL的数据类型和 Python 的数据类型有什么区别呢?我一脸懵逼啊 这两者的数据类型有什么直接的关系么,于是经过我的和众多网民的分析,最终的得出一个脑残级别的结论: SQL 是查询导出数据的,而 Python 则是分析数据的,一个是数据的计算,一个是数据的处理,两者并没有冲突。
但是我还是非常无聊的总结了一下 MySQL 和 Python 数据类型和对数据处理方面的知识。以此来复习一下 MySQL 和 Python 的基本知识
但是我本文还是重点说一下MySQL的数据类型,以及别人和我的一些经验
数据类型
所有的标准 SQL 中的数据类型几乎在 MySQL 里面都有
数字类型:
MySQL数据类型
整形:int,tinyint,smallint,bigint ,medium 浮点型: float,double,decimal
整形
| 类型 | 占用的空间大小(字节) | 取值范围(Signed) |取值范围(Unsigned)| | :-: | :—————-: | :—————: | :—-:| |int|4|-2147483648-2147483647|0-4294967295| |tinyint|1|-128-127|0-255| |smallint|2|-32768-32767|0-65535| |medium|3|-8388608-8388607|0-16777215| |bigint|8|-9223372036854775808-9223372036854775807|0-18446744073709551615|
Signed & Unsigned
最直观的显示就是有没有符号 有符号就是从负数到正数,无符号的话就是从0开始的值,但是!推荐不使用 unsigned
使用 unsigned
是有一定风险的,有溢出的现象
但是一旦出现溢出现象解决的办法也是有的:
解决 set sql_mode='NO_UNSIGNED_SUBTRACTION
Auto_increment
自增,每张表最多只能有一个,而且必须是索引的一部分
Zerofill
只是负责 显示属性,值不做任何修改
浮点型
单精度类型:float,4个字节 双精度类型:duble,8个字节 高精度类型:decimal,可变长度
- float(M,D),duble(M,D),decimal(M,D) M为整数位,D为小数位
- 财务、账务系统必须用DECIMAL类型 。
字符串类型
char(n) 定长字符字符 (n 表示字符 ) vachar(n) 变长字符(n 表示字符)
尽量使用varchar而不要使用char
text,tinytext,mediumtext,longtext 都是大对象
text 可以理解 为 varchar
binary(n) 定长二进制字节(n 表示字节 ) varbinary(n) 变长二进制字节(n 表示字节 )
blob,tinyblob ,mediumblob,longblog 都是二进制大对象
blob 可以理解为 varbinary
mysql> select @@global.max_sort_length;
+--------------------------+
| @@global.max_sort_length |
+--------------------------+
| 1024 |
+--------------------------+
1 row in set (0.00 sec)
字符集
在 MySQL 字符串类型里面 char
,varchar
,text
,tinytext
,mediumtext
,longtext
是有字符集(一组符号和编码的集合)概念的
在数据库里面,常见的字符集有:utf8mb4
,utf8
,gbk
,gb18030
其中:
- 尽量用
utf8mb4
因为utf8
在表情上面可能是乱码 gb18030
在MySQL5.7版本才支持mysql> show character set;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| dec8 | DEC West European | dec8_swedish_ci | 1 |
| cp850 | DOS West European | cp850_general_ci | 1 |
| hp8 | HP West European | hp8_english_ci | 1 |
| koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 |
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 |
| swe7 | 7bit Swedish | swe7_swedish_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| ujis | EUC-JP Japanese | ujis_japanese_ci | 3 |
| sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 |
| hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 |
| tis620 | TIS620 Thai | tis620_thai_ci | 1 |
| euckr | EUC-KR Korean | euckr_korean_ci | 2 |
| koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 |
| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |
| greek | ISO 8859-7 Greek | greek_general_ci | 1 |
| cp1250 | Windows Central European | cp1250_general_ci | 1 |
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
| latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 |
| armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 |
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |
| cp866 | DOS Russian | cp866_general_ci | 1 |
| keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 |
| macce | Mac Central European | macce_general_ci | 1 |
| macroman | Mac West European | macroman_general_ci | 1 |
| cp852 | DOS Central European | cp852_general_ci | 1 |
| latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
| cp1251 | Windows Cyrillic | cp1251_general_ci | 1 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| cp1256 | Windows Arabic | cp1256_general_ci | 1 |
| cp1257 | Windows Baltic | cp1257_general_ci | 1 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| binary | Binary pseudo charset | binary | 1 |
| geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 |
| cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 |
| eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 |
+----------+-----------------------------+---------------------+--------+
40 rows in set (0.08 sec)
设置字符集:有三种方法:
1.设置全局字符集 :设置配置参数 character_set_sever = xxx
2 建立数据库和表或者列的时候 指定字符集例如:
CREATE TABLE `student` (
`studentId` int(11) NOT NULL CHARSET utf8mb4,
`studentName` varchar(10) NOT NULL CHARSET utf8mb4,
`studentAge` int(11) NOT NULLCHARSET utf8mb4
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
collection 排序规则
默认的排序规则是不区分大小写 ,忽略空格
mysql> select 'a'='a';
+---------+
| 'a'='a' |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
mysql> select 'a'='A';
+---------+
| 'a'='A' |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
mysql> select 'a'='A ';
+----------+
| 'a'='A ' |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
如果大小写区分 不忽略空格 排序规则应该设置成 utf8mb4_bin
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)
mysql> select ' a'='a';
+----------+
| ' a'='a' |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
mysql> select 'a'='A';
+---------+
| 'a'='A' |
+---------+
| 0 |
+---------+
1 row in set (0.00 sec)
集合类型
MySQL 特有的 枚举型和集合类型 :enum
& set
可以用于约束的检查代替SQL_Server里面定义的约束:和 sql_mode
配合使用,设置成严格模式,SET SQL_MODE='strict_trans_tables'
比如说:性别 sex enum('male','female')
当插入除了male和female 以外的值的时候是会报错,因为数据的一致性受到破坏 。
枚举类型和集合类型本身存储是很高效的 。 必须配合sql_mode
使用 ,不然插入以外的值是不会报错的,但是本身插入的是一个null 。
mysql> CREATE TABLE `test` (
-> sex ENUM('male','female')
-> );
Query OK, 0 rows affected (0.36 sec)
mysql> INSERT INTO test SELECT 'male';
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> INSERT INTO test SELECT 'a';
Query OK, 1 row affected, 1 warning (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 1
mysql> SELECT * FROM test;
+------+
| sex |
+------+
| male |
| |
+------+
2 rows in set (0.00 sec)
mysql> SET SQL_MODE='strict_trans_tables';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO test SELECT 'b';
ERROR 1265 (01000): Data truncated for column 'sex' at row 1
日期类型
year,data,time,datatime,timestamp
类型 | 占用的空间大小(字节) | 取值范围 |
---|
year | 1 | YEAR(2): 1970~ 2070 YEAR(4): 1901~ 2155 |
data | 3 | 1000-01-01~ 9999-12-31 |
time | 3 | -838:59:59~ 838:59:59 |
datatime | 8 | 1000-01-01 00:00:00~ 9999-12-31 23:59:59 |
timestamp | 4 | 1970-01-01 00:00:00 UTC~2038-01-19 03:14:07 UTC |
日期函数
now
:返回执行时的时间 current_timestamp
:返回执行时的时间 sysdate
:返回执行函数时的时间 date_add(date,INTERVALexprunit)
:增加时间 date_sub(date,INTERVALexprunit)
:减少时间 date_format
:格式化时间显示
mysql> select now(),sysdate(),sleep(5),now(),sysdate();
+---------------------+---------------------+----------+---------------------+--
-------------------+
| now() | sysdate() | sleep(5) | now() | sysdate() |
+--------+-----------+----------+----------+--------+
| 2017-02-10 13:36:51 | 2017-02-10 13:36:51 | 0 | 2017-02-10 13:36:51 | 2017-02-10 13:36:56 |
+---------------------+---------------------+---+---------------------+---------------------+
1 row in set (5.02 sec)
JSON 类型
MySQL 5.7版本开始支持非结构化数据类型 JSON
,用户可以在数据库级别操作 JSON 的任意键值和数据。 ``` mysql> CREATE TABLE test_two ( id int auto_increment, -> data json, -> primarykey(uid) -> ); Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO test_two values (NULL, -> ‘{“name”:”zhangsan”,”mail”:”xxx@xxx.com”,”string”: “Hello World”}’); Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO test_two values (NULL,”a”); ERROR 3130 (22032): Invalid JSON text: “Invalid value” at position 2 in value (or column) ‘a’.
在MySQL官方文档摘录的一部分介绍如下:
提供的与json类型相关的函数
JSON_APPEND() JSON_ARRAY_INSERT() JSON_UNQUOTE() JSON_ARRAY() JSON_REPLACE() JSON_CONTAINS() JSON_DEPTH() JSON_EXTRACT() JSON_INSERT() JSON_KEYS() JSON_LENGTH() JSON_VALID() JSON_MERGE() JSON_OBJECT() JSON_QUOTE() JSON_REMOVE() JSON_CONTAINS_PATH() JSON_SEARCH() JSON_SET() JSON_TYPE()
函数的调用规则基本可以表示为:
``JSON_APPEND(json_doc, path, val[, path, val] ...)``
参数解释:
* json_doc 为JSON文档,或者是表里面的某一列,也可以是JSON文档里面的嵌套子文档变量
* path 为路径表达式,用来定位要访问的键,更方便快速的访问JSON的键值
* val 可有可无,若有表示键对应的操作数值
用法如下所示:
mysql> select -> json_extract(data, ‘$.name’), -> json_extract(data,’$.mail’) -> from test_two; +—————————–+——————————-+ | jsn_extract(data, ‘$.name’) | jsn_extract(data,’$.address’) | +—————————–+——————————-+ | “zhangsan” | “xxx@xxx.com” | +—————————–+——————————-+ 1 rows in set (0.00 sec) ```
关于 MySQL支持JSON 的问题有机会拿出来单独谈谈
这是一个拼字的小游戏,也不能说是游戏吧,反正就是一个看上去好玩的东西,下面就是它的说明。
写一个Python脚本,以拼字游戏作为命令行参数的脚本和 打印所有有效的拼字,可以由这个脚本,连同他们的拼的字按照分数列出来,示例调用和输出为一下内容
$ python scrabble.py ZAEFIEE
17 feeze
17 feaze
16 faze
15 fiz
15 fez
12 zee
12 zea
11 za
6 fie
6 fee
6 fae
5 if
5 fe
5 fa
5 ef
2 ee
2 ea
2 ai
2 ae
URL = http://wiki.openhatch.org/Scrabble_challenge
这上面有具体的要求和步骤:有兴趣的可以好好看看,里面说明了要实现什么样的功能,以及分析每一步都需要做什么,然后你可以根据他的问题自己实现这个功能。
准备工作
1、 word list
” http://courses.cms.caltech.edu/cs11/material/advjava/lab1/sowpods.zip contains all words in the official SOWPODS word list, one word per line. “
要有一个源文件也就是word list,下面给出了这个word list 的下载地址。
点此处下载 sowpods.zip
文件里面的单词我大概截取了一小小小部分,大概是这个样子的
AA
AAH
AAHED
AAHING
AAHS
AAL
AALII
AALIIS
AALS
AARDVARK
AARDVARKS
AARDWOLF
AARDWOLVES
AARGH
AARRGH
AARRGHH
AARTI
AARTIS
AAS
AASVOGEL
AASVOGELS
AB
ABA
ABAC
ABACA
ABACAS
ABACI
2、 letters and values (字母和值)
” Here is a dictionary containing all letters and their Scrabble values “
内容如下:
scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
"f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
"l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
"r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
"x": 8, "z": 10}
解决问题
第一步 construct a word list
” Write the code to open and read the sowpods word file. Create a list, where each element is a word in the sowpods word file. Note that each line in the file ends in a newline, which you’ll need to remove from the word. “
大概就是说
写代码来打开并且读 sowpods Word 文件。创建一个列表,其中每个元素都是 sowpods Word 文件里面的单词。请注意,我们需要删除在文件里面的每一个换行符。
具体的步骤请参考上面的链接。
# 以小写的形式读出来,并且去除换行符
def get_word_to_list(file_name):
word_list = []
with open(file_name, 'r') as f:
for line in f:
lines = line.lower()
word_list.append(lines.strip('\n'))
return word_list
第二步 get the rack
” Write the code to get the Scrabble rack (the letters available to make words) from the command line argument passed to your script. For example if your script were called scrabble_cheater.py
, if you ran python scrabble_cheater.py RSTLNEI, RSTLNEI would be the rack. Handle the case where a a user forgets to supply a rack; in this case, print an error message saying they need to supply some letters, and then exit the program using the exit() function. Make sure you are consistent about capitalization “
说白了就是运行脚本的后面要加上你要操作的单词作为参数,如果没有就打印错误信息,并且退出。
def get_argument_word(word_list):
if len(sys.argv) == 2:
rack = sys.argv[1]
lower_word = rack.lower()
c = coll.Counter(lower_word)
return [word for word in word_list if not (coll.Counter(word) - c)]
else:
print('Usage: scrabble_change.py ABC')
sys.exit()
第三步 find valid words
“Write the code to find all words from the word list that are made of letters that are a subset of the rack letters. There are many ways to do this, but here’s one way that is easy to reason about and is fast enough for our purposes: go through every word in the word lishe word in a valid_words list. Make sure you handle repeat letters: once a letter from the rack has been used, it can’t be used again.”
写的代码要查找所有单词表里面的单词,这些单词都是由字母构成的,然后检查每一个单词表里面符合的单词,确定重复的字母,一旦这个字母被用到了,就不会再次被用到。
第四步 scoring
“Write the code to determine the Scrabble scores for each valid word, using the scores dictionary from above.”
写代码 用上面的成绩字典 来确定每个有效词的拼字游戏的分数。
def get_scores(words):
word_dic = coll.defaultdict(int)
scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
"f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
"l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
"r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
"x": 8, "z": 10}
for word in words:
for s in word:
word_dic[word] += scores[s]
return word_dic
##完整代码
# !/usr/bin/python
# -*- coding: UTF-8 -*-
from __future__ import print_function
import sys
import collections as coll
# lower
def get_word_to_list(file_name):
word_list = []
with open(file_name, 'r') as f:
for line in f:
lines = line.lower()
word_list.append(lines.strip('\n'))
return word_list
def get_argument_word(word_list):
if len(sys.argv) == 2:
rack = sys.argv[1]
lower_word = rack.lower()
c = coll.Counter(lower_word)
return [word for word in word_list if not (coll.Counter(word) - c)]
else:
print('Usage: scrabble_change.py ABC')
sys.exit()
def get_scores(words):
word_dic = coll.defaultdict(int)
scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
"f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
"l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
"r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
"x": 8, "z": 10}
for word in words:
for s in word:
word_dic[word] += scores[s]
return word_dic
# def get_scores(*args):
# dict_set1 = {}
# if 'key' not in dict_set1:
# dict_set1['key'] = set()
# scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
# "f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
# "l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
# "r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
# "x": 8, "z": 10}
# for word in args:
# for s in word:
# total_scores += scores[s]
# return total_scores, word
def main():
word_list = get_word_to_list('sowpods.txt')
valid_words = get_argument_word(word_list)
d = get_scores(valid_words)
for key, val in sorted(d.items(), key=lambda item: item[1], reverse=True):
print(val, key)
if __name__ == '__main__':
main()
解决几处问题:
def get_word_to_list(file_name):
word_list = []
with open(file_name, 'r') as f:
for line in f:
lines = line.lower()
word_list.append(lines.strip('\n'))
return word_list
上面的代码是把文件里面的单词全部转换为小写读到数组里面,但是文件很大,比如我只需要列出几个或者几十个单词,并不需要把所有的单词都列出来
像这样
$ python scrabble.py ZAEFIEE
17 feeze
17 feaze
16 faze
15 fiz
15 fez
12 zee
12 zea
11 za
6 fie
6 fee
6 fae
5 if
5 fe
5 fa
5 ef
2 ee
2 ea
2 ai
2 ae
所以,可以改正一下,就是把输出的单词全部以小写的形式表现出来。
更改一番
# !/usr/bin/python
#-*- coding: UTF-8 -*-
from __future__ import print_function
import sys
from collections import Counter
scores = {"a": 1, "c": 3, "b": 3, "e": 1, "d": 2, "g": 2,
"f": 4, "i": 1, "h": 4, "k": 5, "j": 8, "m": 3,
"l": 1, "o": 1, "n": 1, "q": 10, "p": 3, "s": 1,
"r": 1, "u": 1, "t": 1, "w": 4, "v": 4, "y": 4,
"x": 8, "z": 10}
def get_word_list(file_name):
word_list = []
with open(file_name) as f:
for line in f:
word_list.append(line.strip('\n'))
return word_list
def get_valid_words(word_list, rack):
c = Counter(rack)
return [ word for word in word_list if not (Counter(word) - c) ]
def lower_valid_words(words):
return [ word.lower() for word in words ]
def get_scores(words):
d = {}
for word in words:
d[word] = sum(scores[c] for c in word)
return d
def main():
if len(sys.argv) != 2:
raise SystemExit('Usage: scrabble_change.py RACK')
rack = sys.argv[1]
word_list = get_word_list('sowpods.txt')
valid_words = get_valid_words(word_list, rack.upper())
valid_words = lower_valid_words(valid_words)
d = get_scores(valid_words)
for val, key in sorted(zip(d.values(), d.keys()), reverse=True):
print(val, key)
if __name__ == '__main__':
main()
前几日看到有人讨论说一个Python的面试题,题目是这样的: 有一个数据文件,是csv格式,大约1T数据,要导入到MySQL,要求正确高效。 csv数据格式这个样子的
[root@iZ28b4rx8dxZ ~]# cat data.csv
id,name,sex,age
1,张三,女,18
2,李四,男,19
正好最近要写再测试数据库的脚本,虽然两者不搭边,总归都是操作数据库的,正好测试的时候就用python连了
首先 Python 数据库接口支持很多数据库,什么关系型的像 mysql 啊、PG(PostgreSQL) 啊、SQL Server、Oracle,非关系型的像 MongoDB 啊,Redis 啊, Hbase 等等,
这里就以MySQL数据库为例,毕竟我要用的MySQL嘛,而且面试题也是,当然操作其他数据库道理也都一样,从一个 csv 文件中读入数据,插入到数据库中,再将数据库中的数据读出,保存到另一个csv文件。
#介绍
主要定义两个对象,一个用于管理连接的 Connection(count) 了,另一个是用于执行查询的 Cursor (cur)对象。
##Python 操作数据库的大致思路
##步骤:
导入数据库模块 import MySQLdb
连接数据库 connect
,返回一个 conn
对象
通过该对象的 cursor()
成员函数返回一个 cur
对象
通过 cur
对象的 execute()
方法执行SQL语句
关闭 cur
和 conn
对象
#把csv中的数据读出来放到插入到mysql表
对于mysql 数据库,需要安装第三方模块Mysql-python 。安装完以后,在程序中导入模块即可。
库名:test 表名:student
csv和数据库表的结构都是这样的
id | name | sex | age |
---|
1 | 张三 | 女 | 18 |
2 | 李四 | 男 | 20 |
3 | 王二 | 男 | 19 |
首先要导入MySQLdb模块先安装MySQLdb
pip install MySQLdb
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# This is a script that writes data from CSV to MySQL
import csv
import MySQLdb
def main():
# 连接数据库
conn = MySQLdb.connect(
host='localhost',
port=3306,
user='root',
passwd='123',
db='test',
)
cur = conn.cursor()
# 创建数据表
cur.execute("DROP TABLE IF EXISTS `student`")
conn.commit()
create_db = """create table student(
id int,
name varchar(10),
sex char(4),
age int
)
ENGINE=InnoDB DEFAULT CHARSET=utf8"""
cur.execute(create_db) #执行创建表语句
conn.commit()
# 把 CSV 读到数组里
f = open("/var/python_code/input_CSV_file.csv", 'r')
student = []
for row in csv.reader(f):
student.append(row)
f.close()
# 还可以替换成为with
# student = []
# with open("/var/python_code/input_CSV_file.csv", 'r') as f:
# for row in csv.reader(f):
# student.append(row)
# 执行 insert
insert_db = "insert into student values(%s, %s, %s, %s)"
cur.executemany(insert_db, student) #批量高效插入
conn.commit()
# 关闭连接
if cur:
cur.close()
if conn:
conn.close()
if __name__ == '__main__':
main()
不得不提一下
executemany()
是对数据进行批量插入如果对效率有要求的时候 最合适不过的选择了,原理大概就是将数组中的元素一个个取出来然后一条条的执行,在这之前我曾尝试过用 execute(),当时是从文件里面读出一行写入到数据可一行,后来我仔细想了一下,如果数据量很大呢,就像面试题说的,如果 1T 的数据呢,估计得等到驴年马月,估计公司也会see by . 于是果断把代码删掉重写成:把文件里面的内容全部读出来写入到数组里,然后用 executemany()
执行批量插入了
#执行查询语句,并将结果输出到CSV文件里
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# This is a script that writes data from MySQL to csv
import csv
import MySQLdb
def main():
# 连接数据库
conn = MySQLdb.connect(
host='localhost',
port=3306,
user='root',
passwd='123',
db='test',
)
cur = conn.cursor()
# 以写的方式打开 csv 文件并将内容写入到w
f = open("/var/python_code/output_CSV_file.csv", 'w')
write_file = csv.writer(f)
# 从 student 表里面读出数据,写入到 csv 文件里
cur.execute("select * from student")
while True:
row = cur.fetchone() #获取下一个查询结果集为一个对象
if not row:
break
write_file.writerow(row) #csv模块方法一行一行写入
f.close()
# 关闭连接
if cur:
cur.close()
if conn:
conn.close()
if __name__ == '__main__':
main()
之前写过一篇文章是关于搭建FTP的,当时是一时心血来潮,随便弄了一下其中出了一部分错误,也没有具体的记录下来,最近由于一些原因,需要自己重新拿过来好好研究一下,于是又开始研究起来,具体的搭建过程我就不说了,搭建中详细的内容可以参考
搭建简单FTP服务器以及遇到的几个问题(一)
上篇文章主要讲述FTP是干嘛的,为什么要用到,以及如何搭建部署,匿名非匿名等等
本篇文章 主要讲述了
根据我重新实践对于过程中遇到的几个问题以及可能遇到的几个问题详细总结一下,作为一下参考。
#1. 首先匿名用户:
[root@iZ28b4rx8dxZ vsftpd]# vim /etc/vsftpd/vsftpd.conf
anonymous_enable=YES
//匿名用户可以访问
连接FTP,进入主目录,发现可以查看但是不能创建目录上传文件
##错误信息:
状态: 正在创建目录“/pub/创建目录”...
命令: MKD 创建目录
响应: 550 Permission denied.
命令: MKD /pub/创建目录
响应: 550 Permission denied.
分析错误原因
1. 配置文件
解决办法
[root@iZ28b4rx8dxZ vsftpd]# vim /etc/vsftpd/vsftpd.conf
write_enable=NO
需要把NO改为YES或者直接#注释掉,并且允许匿名账户可删除创建更名权限
#write_enable=NO
write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
重启FTP
[root@iZ28b4rx8dxZ vsftpd]# service vsftpd restart
Restarting vsftpd (via systemctl): [ OK ]
###2. FTP用户权限配置有问题
解决办法
检查一下FTP用户的主目录是否存在以及用户是否有权限访问主目录。
进入FTP 的主目录修改为ftp用户ftp用户组,注意权限755
[root@iZ28b4rx8dxZ ftp]# chown ftp:ftp /var/ftp/pub/
[root@iZ28b4rx8dxZ ftp]# chmod 755 /var/ftp/pub/
[root@iZ28b4rx8dxZ ftp]# ll /var/ftp/
total 4
drwxr-xr-x 2 ftp ftp 4096 Nov 6 03:43 pub
[root@iZ28b4rx8dxZ vsftpd]# service vsftpd restart
Restarting vsftpd (via systemctl): [ OK ]
#2. 匿名用户禁止访问
更改配置文件:
[root@iZ28b4rx8dxZ vsftpd]# vim /etc/vsftpd/vsftpd.conf
anonymous_enable=NO
//匿名禁止访问
添加用户名密码
##错误信息
响应: 530 Login incorrect.
错误: 严重错误: 无法连接到服务器
##分析错误原因
1. FTP密码不正确导致
解决办法
可重置FTP密码后再做登录测试。
[root@iZ28b4rx8dxZ ~]# passwd ftpuser
Changing password for user ftpuser.
New password:
BAD PASSWORD: it is WAY too short
BAD PASSWORD: is too simple
Retype new password:
passwd: all authentication tokens updated successfully.
[root@iZ28b4rx8dxZ ~]#
2. FTP用户权限配置有问题
检查一下FTP用户的主目录是否存在以及用户是否有权限访问主目录。
进入FTP 的主目录修改为ftp用户ftp用户组,注意权限755
[root@iZ28b4rx8dxZ ftp]# chown ftp:ftp /var/ftp/pub/
[root@iZ28b4rx8dxZ ftp]# chmod 755 /var/ftp/pub/
[root@iZ28b4rx8dxZ ftp]# ll /var/ftp/
total 4
drwxr-xr-x 2 ftp ftp 4096 Nov 6 03:43 pub
[root@iZ28b4rx8dxZ vsftpd]# service vsftpd restart
Restarting vsftpd (via systemctl): [ OK ]
3. FTP限制
vim /etc/vsftpd/vsftpd.conf
更改配置文件为
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user
然后以一个用户一行的形式加到 /etc/vsftpd/user
文件中,然后重启ftp
连接ftp
状态: 正在连接 *********:21...
状态: 连接建立,等待欢迎消息...
状态: 不安全的服务器,不支持 FTP over TLS。
状态: 已连接
状态: 读取目录列表...
状态: 列出“/var/ftp/pub”的目录成功
状态: 正在创建目录“/var/ftp/pub/创建目录”...
状态: 读取“/var/ftp/pub/创建目录”的目录列表...
状态: 列出“/var/ftp/pub/创建目录”的目录成功
状态: 开始上传 入门.pdf
状态: 读取“/var/ftp/pub/创建目录”的目录列表...
状态: 列出“/var/ftp/pub/创建目录”的目录成功
状态: 正在删除“/var/ftp/pub/创建目录/入门.pdf”
状态: 读取“/var/ftp/pub”的目录列表...
状态: 列出“/var/ftp/pub”的目录成功
上一篇提过了字符集的历史其中也简单的提到了 Unicode
与 utf-8
的关系,下面本文主要介绍了Python中的 Unicode 和 utf-8 : utf-8和utf-16 、utf-32是一类,实现的功能是一样的,只是utf-8使用的最为广泛,但是Unicode和utf-8并不是同一类,Unicode是表现形式,utf-8是存储形式
#Python中的Unicode和utf-8
理解:存储的时候需要编码成utf-8,表现的时候是一个utf-8需要解码成为Unicode,换句话说,在代码中处理的是Unicode,在文件中存储的时候是以utf-8的形式存储。
##不使用Unicode的形式
In [1]: name = '张三'
In [2]: print name
张三
In [3]: name
Out[3]: '\xe5\xbc\xa0\xe4\xb8\x89' #utf8编码,存储形式
In [4]: len(name)
Out[4]: 6
In [5]: name[0:2] #分片操作
Out[5]: '\xe5\xbc'
In [6]: print name[0:1]
�
In [7]: type(name) #类型是字符串类型
Out[7]: str
In [8]: type
##使用Unicode的形式:
Python2里面,是直接在字符串前面加一个u
In [8]: name = u'张三'
In [9]: name
Out[9]: u'\u5f20\u4e09' #Unicode编码 表现形式
In [10]: print name
张三
In [11]: print name[0:1]
张
In [12]: name[0:1]
Out[12]: u'\u5f20'
In [13]: len(name)
Out[13]: 2
In [15]: type(name)
Out[15]: unicode #类型是一个unicode
下面重点来了
#解码函数与编码函数
Unicode与utf-8的互相转换: 在Python里面提供了内置的方法:decode()
、encode()
编码: encode()
:从表现形式到存储形式
解码: decode()
:从存储形式到表现形式
其中Unicode并没有和某一种解码形式绑定起来,
In [37]: name = u'张三'
In [38]: b_name = name.encode('utf-8') #编码为不同的存储形式,既可以编码为utf-8
In [39]: b_name
Out[39]: '\xe5\xbc\xa0\xe4\xb8\x89'
In [47]: type(b_name) #类型为str
Out[47]: str
In [40]: b_name2 = name.encode('utf-16') #也可以编码为utf-16
In [41]: b_name2
Out[41]: '\xff\xfe _\tN'
In [42]: b_name3 = name.encode('utf-32') #还可以编码为utf-32
In [43]: b_name3
Out[43]: '\xff\xfe\x00\x00 _\x00\x00\tN\x00\x00'
In [44]: j_name = b_name.decode('utf-8') #把utf-8解码为Unicode
In [45]: j_name
Out[45]: u'\u5f20\u4e09'
In [46]: type(j_name) #类型为Unicode
Out[46]: unicode
所以综上所述 Unicode
写入到一个文件里面的时候出错,错误提示为:ASCII
编码不能大于128,ASCII
编码范围为0-128,当然汉字超出了 ASCII
的编码范围
对 error
的理解:Unicode为表现形式,具体存储的时候必须要编码成某一种编码的方式,Python2 中默认使用ASCII编码,所以存储ASCII,但是我现在存的是中文,中文的范围比ASCII大很多,所以存不下导致报错:
In [47]: name = u'张三'
In [50]: with open('/tmp/test', 'w') as f:
...: f.write(name)
...:
---------------------------------------------------------------------------
UnicodeEncodeError Traceback (most recent call last)
<ipython-input-4-0d87fa01de83> in <module>()
1 with open('/tmp/test', 'w') as f:
----> 2 f.write(name)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
所以解决办法就有了,先编码为 utf-8
或者 utf-16
等等
In [51]: with open('/tmp/test', 'w') as f:
...: f.write(name.encode('utf-8')) #编码为utf-8形式写入到文件里面
...:
In [52]: with open('/tmp/test', 'r') as f:
...: new_name=f.read()
...:
In [53]: new_name.decode('utf-8') #把utf-8解码为Unicode
Out[53]: u'\u5f20\u4e09'
Python2和Python3关于字符集方面的区别
##Python2和Python3的在字符集方面的差别:
1、Python2里面str表示普通的字符串,而unicode表示的就是一个unicode 也就是说:不指定类型的时候就是一个str,指定为Unicode的时候就是Unicode类型
In [15]: name = u'张三'
In [16]: type(name)
Out[16]: unicode
2、Python3里面不指定字符串类型的时候是一个str。
3、Python3里面的str就是Python2里面的unicode,Python2里面的str是Python3里面的bytes!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
##open函数
###Python2
Python2 中有一个标准库 codecs
模块 帮我们自动编码解码 codecs
模块提供的 open
函数提供一个 encoding
参数
In [55]: import codecs
In [56]: name = u'张三'
In [57]: with open('/tmp/test', 'w', encoding='utf-8') as f:
...: f.write(name)
...:
In [58]: with open('/tmp/test', 'r', encoding='utf-8') as f:
...: new_name=f.read()
...:
In [59]: new_name
Out[59]: u'\u5f20\u4e09'
Python3
Python3 的 open
函数本身就提供了 encoding
参数 我们可以通过 encoding
指定编码,在使用上和 python2
的 codecs
模块一样,
>>> name = '张三'
>>> name
'张三'
>>> with open('/tmp/test', 'w', encoding='utf-8') as f:
... f.write(name)
...
总结!!!!!!!!!!!!!!!!!!!
把Unicode字符表示为二进制数据有许多种办法,最常见的编码方式就是utf-8。!!!!!!!!!!!!! Python3的str和Python2的Unicode,并没有和特定的二进制编码相关联。若想把Unicode字符转换成二进制数据,就必须使用 encode
方法,若想把二进制数据转换成Unicode字符,就必须使用 decode
在编程的时候,一定要把编码和解码操作放在界面最外围来做,程序的核心部分应该使用Unicode字符类型,而不要对字符编码做任何假设。
##Python3
#在Python3中,我们需要编写接受str或bytes,并总是返回str的方法:
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value # Instance of str
#另外,还需要编写接受str或bytes,并总是返回bytes的方法:
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode('utf-8)
else:
value = bytes_or_str
return value # Instance of bytes
##Python2
#在Python2中,需要编写接受str或unicode,并总是返回unicode的方法:
#python2
def to_unicode(unicode_or_str):
if isinstance(unicode_or_str, str):
value = unicode_or_str.decode('utf-8')
else:
value = unicode_or_str
return value # Instance of unicode
#另外,还需要编写接受str或unicode,并总是返回str的方法:
#Python2
def to_str(unicode_or_str):
if isinstance(unicode_or_str, unicode):
value = unicode_or_str.encode('utf-8')
else:
value = unicode_or_str
reutrn vlaue # Instance of str
#参考资料
- 文章下面的部分内容摘自《Effective Python:编写高质量Python代码的59个有效方法》第3 条:了解bytes、str 与unicode 的区别