tonglin0325的个人主页

go学习笔记——配置

1.读取命令行参数

1
2
3
4
func main() {
println("Hello ", os.Args[1])
}

配置arg

输出

1
2
Hello World

注意arg[0]是go程序的运行目录

2.使用flag加载环境变量

golang内置的标准库flag,可以用来读取配置文件的路径

1
2
3
4
5
6
7
func main() {

var configFilePath = flag.String("conf", "./", "config file path") // flag也支持flag.Bool,flag.Int等用法
flag.Parse()
println(*configFilePath)
}

配置

输出

1
2
./configs

如果找不到-conf配置的话,才会输出 ./

3.使用toml或者multiconfig加载toml配置文件

1.使用toml

1
2
go get github.com/BurntSushi/toml@latest

参考:https://github.com/BurntSushi/toml

config.toml配置

1
2
3
4
5
6
Age = 25
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time // requires `import time`
}

func main() {

buf, err := os.ReadFile("./configs/config.toml")
tomlData := string(buf)
if err != nil {
panic(err)
}
var conf Config
if _, err := toml.Decode(tomlData, &conf); err != nil {
fmt.Println(err.Error())
}
fmt.Println(conf)

}

输出

1
2
{25 [Cauchy Plato] 3.14 [6 28 496 8128] 1987-07-05 05:45:00 +0000 UTC}

2.使用multiconfig

1
2
go get github.com/koding/multiconfig

参考:https://github.com/koding/multiconfig

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
func main() {

m := multiconfig.NewWithPath("./configs/config.toml") // supports TOML and JSON

// Get an empty struct for your configuration
conf := new(Config)

// Populated the serverConf struct
m.MustLoad(conf) // Check for error

fmt.Printf("%+v\n", conf)

输出

1
2
&{Age:25 Cats:[Cauchy Plato] Pi:3.14 Perfection:[6 28 496 8128] DOB:1987-07-05 05:45:00 +0000 UTC}

4.使用viper加载配置文件

安装viper

1
2
go get github.com/spf13/viper

在config目录下添加viper.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package config

import "github.com/spf13/viper"

// 全局Viper变量
var Viper = viper.New()

func Load(configFilePath string) error {
Viper.SetConfigName("config") // config file name without file type
Viper.SetConfigType("yaml") // config file type
Viper.AddConfigPath(configFilePath) // config file path
return Viper.ReadInConfig()
}

配置文件

1
2
3
4
db:
mysql:
dsn: root:123456@tcp(127.0.0.1:55000)/test?charset=utf8mb4&parseTime=True

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
func main() {

var configFilePath = flag.String("conf", "./", "config file path")
flag.Parse()

if err := config.Load(*configFilePath); err != nil {
panic(err)
}

println(config.Viper.GetString("db.mysql.dsn"))
}

全文 >>

sublime插件使用

sublime软件支持安装插件来增强功能

Tool->Command Palette->install package

1.sqlbeautifier SQL格式化

command+K,然后command+F,格式化SQL

2.添加行号或者递增的数字

先选中对应的文本,然后按command+shift+L,并command+左箭头 把光标移动行首,如下

再按command+option+N

1:1表示从1开始,每次递增+1,也可以修改成1:2

全文 >>

unblock netease music配置

yaml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
port: 7890
socks-port: 7891
allow-lan: false
mode: Rule
log-level: silent
external-controller: 127.0.0.1:9090
secret: ""
dns:
enable: true
ipv6: false
nameserver:
- https://dns.rubyfish.cn/dns-query
- https://223.5.5.5/dns-query
- https://dns.pub/dns-query
- https://119.29.29.29/dns-query
fallback:
- https://1.0.0.1/dns-query
- https://public.dns.iij.jp/dns-query
- https://dns.twnic.tw/dns-query
fallback-filter:
geoip: true
ipcidr:
- 240.0.0.0/4
- 0.0.0.0/32
- 127.0.0.1/32
domain:
- +.google.com
- +.facebook.com
- +.youtube.com
- +.xn--ngstr-lra8j.com
- +.google.cn
- +.googleapis.cn
- +.gvt1.com
proxies:
- name: "UnblockMusic"
type: http
server: localhost
port: xx
proxy-groups:
-
name: "Netease Music"
type: select
proxies:
- UnblockMusic
- DIRECT
rules:
# Unblock Netease Music
- DOMAIN,api.iplay.163.com,Netease Music
- DOMAIN,apm3.music.163.com,Netease Music
- DOMAIN,apm.music.163.com,Netease Music
- DOMAIN,interface3.music.163.com,Netease Music
- DOMAIN,interface.music.163.com,Netease Music
- DOMAIN,music.163.com,Netease Music
- DOMAIN,interface.music.163.com.163jiasu.com,Netease Music
- DOMAIN,interface3.music.163.com.163jiasu.com,Netease Music
- DOMAIN,music.126.net,Netease Music
- DOMAIN-SUFFIX,163yun.com,Netease Music
- DOMAIN-SUFFIX,mam.netease.com,Netease Music
- DOMAIN-SUFFIX,hz.netease.com,Netease Music

# CIDR规则
- IP-CIDR,39.105.63.80/32,Netease Music
- IP-CIDR,45.254.48.1/32,Netease Music
- IP-CIDR,47.100.127.239/32,Netease Music
- IP-CIDR,59.111.160.195/32,Netease Music
- IP-CIDR,59.111.160.197/32,Netease Music
- IP-CIDR,59.111.181.35/32,Netease Music
- IP-CIDR,59.111.181.38/32,Netease Music
- IP-CIDR,59.111.181.60/32,Netease Music
- IP-CIDR,101.71.154.241/32,Netease Music
- IP-CIDR,103.126.92.132/32,Netease Music
- IP-CIDR,103.126.92.133/32,Netease Music
- IP-CIDR,112.13.119.17/32,Netease Music
- IP-CIDR,112.13.122.1/32,Netease Music
- IP-CIDR,115.236.118.33/32,Netease Music
- IP-CIDR,115.236.121.1/32,Netease Music
- IP-CIDR,118.24.63.156/32,Netease Music
- IP-CIDR,193.112.159.225/32,Netease Music
- IP-CIDR,223.252.199.66/32,Netease Music
- IP-CIDR,223.252.199.67/32,Netease Music
- IP-CIDR,59.111.21.14/31,Netease Music
- IP-CIDR,59.111.179.214/32,Netease Music
- IP-CIDR,59.111.238.29/32,Netease Music

# Advertising
- DOMAIN,admusicpic.music.126.net,REJECT
- DOMAIN,iadmat.nosdn.127.net,REJECT
- DOMAIN,iadmusicmat.music.126.net,REJECT
- DOMAIN,iadmusicmatvideo.music.126.net,REJECT

- DOMAIN-SUFFIX,local,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT
- GEOIP,CN,DIRECT
- MATCH,DIRECT

如果使用yt-dlp音源需要额外安装

R3300L电视盒子刷机

1.先线刷当贝安卓系统到EMMC

  1. 打开USB_Burning_Tool, 打开img文件, Erase flash 和 Erase bootloader 默认勾选. 等着
  2. R3300L断开电源, 开关关上(弹出状态), 顶住AV口内的小开关, 连上USB线,
  3. 等待几秒, 会看到USB_Burning_Tool界面显示Connect success, 然后点击Start
  4. 然后就等进度条一直写到100%
  5. 完成后点击Stop, 关闭USB_Burning_Tool

拔掉USB线, 重新连上HDMI, 加电, 系统开机就是新的安卓系统了

使用的系统是20180123-S905L-R3300L-V12C-root-qlzy

参考:R3300L运行CoreELEC, EmuELEC和Armbia

2.再刷armbian系统到TF卡

双系统不用把armbian系统刷进emmc,需要在安卓系统中安装Reboot to LibreELEC的apk来启动TF卡系统,装上TF卡就自动进行armbian系统

参考:魔百盒R3300L、CM101H以及中兴ZX10 B860AV1.2刷armbian跑甜糖

使用的系统版本是Armbian_20.10_Arm-64_buster_current_5.9.0.img

3.armbian换源

1
2
cp /etc/apt/sources.list /etc/apt/sources.list.bak

换成清华源

1
2
3
4
5
6
7
8
9
10
11
12
deb https://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports main contrib non-free

deb https://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free
#deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free

然后

1
2
apt-get update

如果遇到NO_PUBKEY的报错

1
2
3
Err:4 https://mirrors.tuna.tsinghua.edu.cn/debian buster-backports InRelease
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY XXXXXXXXX NO_PUBKEY XXXXXXXXX

执行下面命令

1
2
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys XXXXXXX

4.安装docker

1
2
armbian-config

1
2
3
root@arm-64:~# docker -v
Docker version 25.0.3, build 4debf41

5.docker部署openwrt

1.部署openwrt

假设armbian的ip是192.168.0.xx

创建network

1
2
docker network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 macnet

启动pod,其中192.168.0.11是openwrt后面会使用的ip

1
2
3
4
5
6
7
8
9
docker run \
-d \
--name=unifreq-openwrt-aarch64 \
--restart=unless-stopped \
--network=macnet \
--privileged \
--ip=192.168.0.11 \
unifreq/openwrt-aarch64:latest

打开网卡混杂模式

1
2
sudo ip link set eth0 promisc on

进入pod查看/etc/config/network文件的option ipaddr,查看其值为192.168.0.1还是192.168.1.1

接着将pod中/etc/config/network的192.168.0.1或者192.168.1.1修改成192.168.0.11

1
2
docker exec unifreq-openwrt-aarch64 sed -e "s/192.168.0.1/192.168.0.11/" -i /etc/config/network

重启pod

1
2
docker restart unifreq-openwrt-aarch64

参考:M401a系列:armbian下docker安装openwrt做旁路由

2.登录openwrt

登录192.168.0.11访问openwrt的管理页面,注意是http的浏览器访问的时候需要接受风险,默认账号密码是root和password

3.设置openwrt

这时候openwrt需要进行一些设置

1.关闭 DHCP

网络 => 接口 => LAN => DHCP 服务器 => 基本设置

操作: 勾选忽略此接口

2.关闭ipv6

网络 => 接口 => LAN => DHCP 服务器 => IPv6 设置

操作: 禁用 路由通告服务, DHCPv6 服务, NDP 代理

3.配置 网关 和 DNS,这样在pod中才能访问网络

网络 => 接口 => LAN => 一般设置 => 基本设置
操作:

  1. IPv4 网关 改为 192.168.0.1
    2. IPv4 广播 改为 192.168.0.255
    3. 使用自定义的 DNS 服务器 改为 114.114.114.114

这时候pod中就可以访问外网了

4.armbian访问openwrt

其中192.168.0.116是armbian机器的ip,192.168.0.11是openwrt的ip

1
2
3
4
5
6
7
8
9
10
11
12
root@arm-64:~# ip link add mynet link eth0 type macvlan mode bridge
root@arm-64:~# ip addr add 192.168.0.116 dev mynet
root@arm-64:~# ip link set mynet up
root@arm-64:~# ip route add 192.168.0.11 dev mynet
root@arm-64:~# ping 192.168.0.11

PING 192.168.0.11 (192.168.0.11) 56(84) bytes of data.
64 bytes from 192.168.0.11: icmp_seq=1 ttl=64 time=1.02 ms
64 bytes from 192.168.0.11: icmp_seq=2 ttl=64 time=0.415 ms
64 bytes from 192.168.0.11: icmp_seq=3 ttl=64 time=0.426 ms
64 bytes from 192.168.0.11: icmp_seq=4 ttl=64 time=0.413 ms

参考:N1 通过 Docker 安装 Openwrt 为旁路由

5.设置软路由ss kx上网

注意需要把软路由接到主路器上

如果不想修改主路由的DNS地址,那么可以通过修改手机的路由器地址到openwrt的ip地址+修改DNS地址到openwrt的ip地址的方式

参考:软路由(operwrt)通过ss Plus+ kx上网教程

全文 >>

各开放平台账号登录API对接文档

当我们开发的系统想要使用第三方账号系统(比如微信,微博,facebook)进行登录的时候,就需要使用第三方平台的登录能力,下面是各第三方平台的对接文档

关于oauth和oauth2.0:理解OAuth 2.0

關於OAuth 2.0-以Facebook為例

1.微信

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

2.微信小程序

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

3.微博

web端

app移动端,可以使用refresh token

https://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6

4.哔哩哔哩

https://openhome.bilibili.com/doc/4/eaf0e2b5-bde9-b9a0-9be1-019bb455701c

全文 >>

Python爬虫——使用selenium和chrome爬取js动态加载的网页

1.使用docker镜像运行selenium+chrome环境

官方镜像仓库selenium/standalone-chrome,只支持amd64

拉取镜像

1
2
docker pull selenium/standalone-chrome:120.0

启动

1
2
docker run -d -p 4444:4444 -p 15900:5900 selenium/standalone-chrome:120.0

其他参数

1
2
docker run -d -p 4444:4444 -p 15900:5900 -e SE_NODE_MAX_SESSIONS=5 --shm-size=2g selenium/standalone-chrome:120.0

参考:https://hub.docker.com/r/selenium/standalone-chrome

访问 localhost:4444/ui 可以查看selenium的运行状态

可以使用mac自带的屏幕共享功能连接pod的vnc

输入 vnc://localhost:15900,默认密码是secret

界面

2.安装依赖

ubuntu/debian换源

1
2
3
4
sudo -s
sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
apt-get update

安装pip3

1
2
apt-get install python3-pip

安装selenium和webdriver-manager

1
2
3
pip3 install selenium
pip3 install webdriver-manager

3.运行selenium

查看chrome和driver version

1
2
3
4
5
root@ced974ac3394:/# google-chrome --version
Google Chrome 120.0.6099.224
root@ced974ac3394:/# chromedriver --version
ChromeDriver 120.0.6099.109 (3419140ab665596f21b385ce136419fde0924272-refs/branch-heads/6099@{#1483})

1.不启用chrome gui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@ced974ac3394:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
driver.get("https://python.org")
print(driver.title)

Welcome to Python.org

exit()

参考:https://github.com/password123456/setup-selenium-with-chrome-driver-on-ubuntu_debian

2.启用chrome gui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@fce0fc2def31:/# python3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--disable-dev-shm-usage')
options.add_argument("--remote-debugging-port=9222") # 不加的话会报session not created: DevToolsActivePort file doesn't exist
options.add_argument('--no-sandbox') # 不加的话会报chrome not reachable
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

此时vnc界面会弹出浏览器

1
2
3
4
>>> driver.get("https://python.org")
>>> print(driver.title)
Welcome to Python.org

打开了python的网页

4.cloudflare人机校验

如果语言cloudflare的人机校验

1.可以尝试使用 undetected_chromedriver 这个包来代替selenium的webdriver

安装 undetected_chromedriver

1
2
pip3 install undetected_chromedriver

替换seleniuim的web driver

1
2
3
4
5
6
7
import undetected_chromedriver as uc

driver = uc.Chrome(headless=False,use_subprocess=False)
driver.maximize_window()
driver.get('https://nowsecure.nl')
driver.save_screenshot('nowsecure.png')

参考:https://github.com/ultrafunkamsterdam/undetected-chromedriver

如果报from session not created: This version of ChromeDriver only supports Chrome version 125

可以在代码中指定chrome的版本,如下

1
2
undetecteddriver = uc.Chrome(options=options, use_subprocess=True, version_main=125)

或者可以尝试使用125.0版本的docker镜像

1
2
docker run -d -p 4444:4444 -p 15900:5900 -e SE_NODE_MAX_SESSIONS=5 --shm-size=2g selenium/standalone-chrome:125.0

2.也可以尝试使用

全文 >>

MySQL学习笔记——多表连接和子查询

多表连接查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 返回的是两张表的乘积
SELECT * FROM tb_emp,tb_dept
SELECT COUNT(*) FROM tb_emp,tb_dept

# 标准写法,每个数据库都能这么写
SELECT * FROM tb_emp CROSS JOIN tb_dept

# 内连接 只列出这些连接表中与连接条件相匹配的数据行
SELECT * FROM tb_emp e,tb_dept d WHERE e.NAME = d.NAME

SELECT * FROM tb_emp INNER JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

# 外链接 不仅列出与连接条件相匹配的行,还列出左表(左外连接),右表(右外连接)或两个表(全外连接)中所有符合where过滤条件的数据行
# 左外连接 在外连接中,某些不满足条件的列也会显示出来,也就是说,只限制其中一个表的行,而不限制另一个表的行
# 左边的表作为主表,左边的表会全部显示
SELECT * FROM tb_emp LEFT JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

#oracle语法,左连接加号在左边
SELECT * FROM tb_emp e,tb_dept d WHERE e.NAME=d.NAME(+)

#右外连接
SELECT * FROM tb_emp RIGHT JOIN tb_dept
ON tb_emp.NAME = tb_dept.NAME

#全外连接 MySQL不支持 OUTER

#自连接
SELECT c.NAME '部门名字',c2.NAME '其他部门'
FROM tb_dept c LEFT JOIN tb_dept c2
ON c.description=c2.id<br /><br /># rollup<br />SELECT orderYear, productLine, SUM(orderValue) totalOrderValue <br />FROM sales <br />GROUP BY orderYear, productline <br />WITH ROLLUP;

参考:https://www.begtut.com/mysql/mysql-rollup.html

全文 >>

HTML学习笔记——基础知识

1.标签

1.title标签、网站关键词、网站描述、实现网页的跳转、单标签、对标签、p标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<!-- title标签 -->
<title>我是title</title>

<!-- 网站关键词 -->
<meta name='keywords' content="切糕,卖切糕,卖切糕"/>

<!-- 网站描述 -->
<meta name='description' content="本网站介绍,要有可读性,100-200字"/>

<!-- 5秒钟后跳转到百度网 -->
<meta http-equiv='refresh' content="5;url='http://www.baidu.com'"/>
</head>



<body>

<!-- 单标签 -->
<img src="/images///images//images/dog.jpg" width="100" height="150" title="图片"/>

<!-- 对标签 -->
[百度](http://www.baidu.com)

**我是strong标签**
<p>我是p标签</p>

</body>
</html>

2.h1标签、h2标签、font标签、加粗文字、下划线、嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
</head>

<body>

<!-- h1文章标题/只能用一次 -->
<h1>我是p标签</h1>

<!-- h2文章标题/可以用多次/权重较低 -->
<h2>我是p标签</h2>

<!-- font/color可以是英文或00ff00/size从1到7 -->
<font color="red" size="7">我是font标签</font>

<!-- 加粗文字 -->
**我是strong标签**

<!-- 嵌套 -->
<font color="red"><u><del>红色文字加下划线</del></u></font>

</body>
</html>

全文 >>

chrome插件ModHeader使用

ModHeader全名modify header,这是一款可以对HTTP请求header进行修改的插件,其支持添加模式Mod过滤器Filter

Mod可以支持对request的header,response的header进行修改,对请求进行重定向redirect等;

Filter支持对特定的URL生效这面的这些Mod

全文 >>

MySQL学习笔记——函数

MySQL函数官方文档可以参考:https://dev.mysql.com/doc/refman/5.7/en/functions.html

1.内置函数和运算符

参考:https://dev.mysql.com/doc/refman/5.7/en/built-in-function-reference.html

1.常用函数

5.流程控制函数

参考:https://dev.mysql.com/doc/refman/5.7/en/flow-control-functions.html

CASE函数

1
2
3
4
5
6
7
8
# 条件判断语句
SELECT NAME,sex,age '原来年龄'
CASE
WHEN age IS NULL THEN 100
ELSE age
END AS '年龄'
FROM tb_emp;

IF()函数

1
2
3
4
5
6
7
8
# IF(expr1,expr2,expr3),如果expr1是True,返回expr2,否则返回expr3
mysql> SELECT IF(1>2,2,3);
-> 3
mysql> SELECT IF(1<2,'yes','no');
-> 'yes'
mysql> SELECT IF(STRCMP('test','test1'),'no','yes');
-> 'no'

IFNULL()函数

1
2
3
4
5
6
7
8
9
10
# IFNULL(expr1,expr2),如果字expr1不为NULL,则返回expr1,如果为NULL,则返回expr2 
mysql> SELECT IFNULL(1,0);
-> 1
mysql> SELECT IFNULL(NULL,10);
-> 10
mysql> SELECT IFNULL(1/0,10);
-> 10
mysql> SELECT IFNULL(1/0,'yes');
-> 'yes'

NULLIF()函数

1
2
3
4
5
6
# NULLIF(expr1,expr2),如果expr1=expr2,则返回NULL,否则返回expr1
mysql> SELECT NULLIF(1,1);
-> NULL
mysql> SELECT NULLIF(1,2);
-> 1

6.数值函数和操作符

参考:https://dev.mysql.com/doc/refman/5.7/en/numeric-functions.html

使用CEIL(x)函数/CEILING(x)函数返回不小于x的最小整数值

1
2
3
4
5
mysql> SELECT CEILING(1.23);
-> 2
mysql> SELECT CEILING(-1.23);
-> -1

使用FLOOR(x)函数返回不大于x的最大整数值

1
2
3
mysql> SELECT FLOOR(1.23), FLOOR(-1.23);
-> 1, -2

使用ROUND()函数保留N位小数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SELECT ROUND(-1.23);
-> -1
mysql> SELECT ROUND(-1.58);
-> -2
mysql> SELECT ROUND(1.58);
-> 2
mysql> SELECT ROUND(1.298, 1);
-> 1.3
mysql> SELECT ROUND(1.298, 0);
-> 1
mysql> SELECT ROUND(23.298, -1);
-> 20
mysql> SELECT ROUND(.12345678901234567890123456789012345, 35);
-> 0.123456789012345678901234567890

使用RAND()函数生成随机数

1
2
3
4
5
6
7
8
9
mysql> select RAND() from user limit 3;
+---------------------+
| RAND() |
+---------------------+
| 0.1310934062405428 |
| 0.8610111650647699 |
| 0.9117756373358663 |
+---------------------+

7.日期和时间函数

参考:https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 返回当前
SELECT NOW();

# 查询时间是1981年
SELECT * FROM tb_emp
WHERE YEAR(diredate) = 1981
AND MONTH(diredate) = 1982;

#插入时间
INSERT INTO tb_emp(NAME,sex,age,address,email,dept_id,diredate)
VALUES('ZHOU','男',33,'香港','ZHOU@163.com',2,'1988-09-09');

INSERT INTO tb_emp(NAME,sex,age,address,email,dept_id,diredate)
VALUES('CAI','女',30,'香港','CAI@163.com',2,NOW());

8.字符串函数和操作符

参考:https://dev.mysql.com/doc/refman/5.7/en/string-functions.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# concat 连接字符串
SELECT CONCAT(NAME,sex) FROM tb_emp;

# UPPER 转换大写/LOWER 转换小写
SELECT UPPER(NAME) FROM tb_emp WHERE dept_id=1;
SELECT LOWER(NAME) FROM tb_emp WHERE dept_id=1;


# 返回字符串长度
SELECT LENGTH(NAME) FROM tb_emp WHERE dept_id=1;

# 返回部分字符
SELECT SUBSTR(NAME,2,2) FROM tb_emp WHERE dept_id=1;

# 比较字符串,按顺序比较,相等返回0,如果第一个的字符小于第二个,返回-1,否则返回1
mysql> SELECT STRCMP('text', 'text2');
+-------------------------+
| STRCMP('text', 'text2') |
+-------------------------+
| -1 |
+-------------------------+
mysql> SELECT STRCMP('text', 'texu');
+------------------------+
| STRCMP('text', 'texu') |
+------------------------+
| -1 |
+------------------------+
mysql> SELECT STRCMP('text', 'texa');
+------------------------+
| STRCMP('text', 'texa') |
+------------------------+
| 1 |
+------------------------+
mysql> SELECT STRCMP('text', 'texa1');
+-------------------------+
| STRCMP('text', 'texa1') |
+-------------------------+
| 1 |
+-------------------------+

19.聚合函数

参考:https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions-and-modifiers.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 聚合函数,也叫组合函数,忽略空值
SELECT AVG(age) FROM tb_emp;
SELECT SUM(age) FROM tb_emp;
SELECT MAX(age) FROM tb_emp;
SELECT MIN(age) FROM tb_emp;
SELECT AVG(age) AS '平均年龄',SUM(age) AS '总年龄',MAX(age) AS '最高年龄',MIN(age) AS '最低年龄'
FROM tb_emp WHERE dept_id=1;

# COUNT不统计null,统计的是行数/记录数
SELECT COUNT(*) FROM tb_emp
SELECT COUNT(email) FROM tb_emp

# 不统计重复记录
SELECT COUNT(DISTINCT diredate) FROM tb_emp

# 分组统计 GROUP BY
# 每个部门的平均年龄
SELECT dept_id,AVG(age) FROM tb_emp GROUP BY dept_id

SELECT dept_id,AVG(age),address FROM tb_emp GROUP BY dept_id,address

# 限定查询结果 HAVING 不能使用where,where子句中不可以使用函数
SELECT dept_id,AVG(age) FROM tb_emp GROUP BY dept_id
HAVING AVG(age)>23
ORDER BY AVG(age) DESC;

# LIMIT 常用来分页
SELECT * FROM tb_emp LIMIT 5; #查询前5个记录
SELECT * FROM tb_emp LIMIT 5,10; #查询前6-10个记录

# group_concat,先聚合,再返回concat后的字符串
select username, group_concat(email),count(1) as cnt from user group by username having cnt > 1;
# 输出
+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+-----+
| username | group_concat(email) | cnt |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+-----+
| jshellshear0 | jshellshear0@prlog.org,jshellshear0@taobao.com | 2 |
| test | ,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test,test@test | 16 |
+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+-----+

全文 >>