mysql多表查询
数据导入
对于——scott_data.sql
#如果不存在,则创建
create database if not exists scott character set utf8;
#选择数据库
use scott;
#创建表
create table bonus
(
ename VARCHAR(10),
job VARCHAR(9),
sal int,
comm int
);
create table dept
(
deptno int not null,
dname VARCHAR(14),
loc VARCHAR(13)
);
#修改表的信息
alter table dept
add constraint PK_DEPT primary key (deptno);
create table emp
(
empno int not null,
ename VARCHAR(10),
job VARCHAR(9),
mgr int,
hiredate DATE,
sal int,
comm int,
deptno int
)
;
alter table emp
add constraint PK_EMP primary key (EMPNO);
alter table emp
add constraint FK_DEPTNO foreign key (DEPTNO)
references dept (DEPTNO);
create table salgrade
(
grade int,
losal int,
hisal int
)
;
#插入数据
insert into dept (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK'),
(20, 'RESEARCH', 'DALLAS'),
(30, 'SALES', 'CHICAGO'),
(40, 'OPERATIONS', 'BOSTON');
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, null, 20),
(7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30),
(7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30),
(7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, null, 20),
(7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30),
(7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, null, 30),
(7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, null, 10),
(7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000, null, 20),
(7839, 'KING', 'PRESIDENT', null, '1981-11-17', 5000, null, 10),
(7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500, 0, 30),
(7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100, null, 20),
(7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, null, 30),
(7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, null, 20),
(7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, null, 10);
insert into salgrade (grade, losal, hisal)
values (1, 700, 1200),
(2, 1201, 1400),
(3, 1401, 2000),
(4, 2001, 3000),
(5, 3001, 9999);
执行
mysql内连接——inner join
例子:显示:员工号,员工姓名,部门编号,部门名称
例子:显示:员工号,姓名,薪水,薪水级别
mysql外连接
右外连接——表在右边
左外连接——表在左边
mysql的约束
约束的种类:
- 主键——自动增长 auto_increment
- 外键
- 非空
- 唯一
创建一个数据库表——myclass
timestap时间戳
由于id属于自动增长类型,timestap(时间戳)也是自动生成的。因此,像表中插入数据的操作过程如下:
创建表——student,使其classid与myclass中的id相关联
向其中插入数据,可以看出,student表中设置的name不重复,以及与myclass相关联是生效的(因为myclass里面没有序号为9的class,所以会插入失败)
mysql中出现中文乱码的原因
mysql自身设计问题
1、以不同字符集登录导致的格式混乱
以utf-8登录数据库,通过如下语句查看数据库中所有应用的字符集种类
上图中8个字符集,与我们有关的是6个(除去filesystem和dir之后余下六个)
一gbk登录数据库,通过如下语句查看数据库中所有字符集种类发现与以utf-8登录的存在差异
因此,通过不同的字符集进行登录,存储的数据之间就会出现格式的混乱
注意:因为字符集错了而导致的报错的不可信的。
2、由于操作系统的语言集导致中文乱码
分别查看本地虚拟机以及阿里云虚拟机中的字符集
其中zh_CN.UTF-8表示——菜单显示按照简体中文,数据存储按照utf8
UTF-8的时候数据存储是不受影响的,其他就不好说了。
当数据存储并不是按照utf-8时,输入的中文数据在存储的过程中有可能会消失,然而存储数据过程并不会发生报错。因此这种错误很难排查。
nysql的api编程
依赖的文件
/usr/include/mysql/mysql.h
/usr/lib64/mysql/libmysqlclient.a
除了用find查找,还可以用locate命令进行查找数据(ubuntu下好使)
locate找的更快,是因为有底层的数据库映射。缺点就是实时性不好。
实现——登录mysql,退出mysql
- mysql_init 初始化
- mysql_real_connect 连接到数据库
- mysql_close 关闭连接
mysql_init()
MYSQL *mysql_init(MYSQL *mysql)
描述
分配或初始化与mysql_real_connect()相适应的MYSQL对象。如果mysql是NULL指针,该函数将分配、初始化、并返回新对象。否则,将初始化对象,并返回对象的地址。如果mysql_init()分配了新的对象,当调用mysql_close()来关闭连接时。将释放该对象。
返回值
初始化的MYSQL*句柄。如果无足够内存以分配新的对象,返回NULL。
错误
在内存不足的情况下,返回NULL。
mysql_real_connect()
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host,
const char *user, const char *passwd,
const char *db, unsigned int port,
const char *unix_socket, unsigned long client_flag)
描述
mysql_real_connect()尝试与运行在主机上的MySQL数据库引擎建立连接。在你能够执行需要有效MySQL连接句柄结构的任何其他API函数之前,mysql_real_connect()必须成功完成。
参数的指定方式如下:
host 主机 ip
user 用户名(数据库)
passwd 密码
db 要登录的库名
port 端口 默认填0
- mysql 默认端口 3306
- oracle 默认端口 1521
- mongodb 默认端口 27017
unix_socket 套接字,默认填NULL
client_flag 客户端标志,一般填0
- 第1个参数应是已有MYSQL结构的地址。调用mysql_real_connect()之前,必须调用mysql_init()来初始化MYSQL结构。通过mysql_options()调用,可更改多种连接选项。
- host”的值必须是主机名或IP地址。如果“host”是NULL或字符串"localhost",连接将被视为与本地主机的连接。如果操作系统支持套接字(Unix)或命名管道(Windows),将使用它们而不是TCP/IP连接到服务器。
- “user”参数包含用户的MySQL登录ID。如果“user”是NULL或空字符串"",用户将被视为当前用户。在UNIX环境下,它是当前的登录名。在Windows ODBC下,必须明确指定当前用户名。
- “passwd”参数包含用户的密码。如果“passwd”是NULL,仅会对该用户的(拥有1个空密码字段的)用户表中的条目进行匹配检查。这样,数据库管理员就能按特定的方式设置MySQL权限系统,根据用户是否拥有指定的密码,用户将获得不同的权限。
示例:
MYSQL mysql;
mysql_init(&mysql);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0)) {
fprintf(stderr, "Failed to connect to database: Error: %s\n",
mysql_error(&mysql));
}
通过使用mysql_options(),MySQL库将读取my.cnf文件的[client]和[your_prog_name]部分,以确保程序工作,即使某人以某种非标准的方式设置MySQL也同样。
注意,一旦建立了连接,mysql_real_connect()将设置再连接标志(MYSQL结构的组成部份)的值,在低于5.0.3版的API中,将其设为“1”,在较新的版本中,将其设为“0”。对于该标志,值“1”表示,如果因连接丢失而无法执行语句,放弃前,将尝试再次连接到服务器。从MySQL 5.0.13开始,可以对mysql_options()使用MYSQL_OPT_RECONNECT选项,对再连接行为进行控制。
mysql_close()
void mysql_close(MYSQL *mysql)
描述
关闭前面打开的连接。如果句柄是由mysql_init()或mysql_connect()自动分配的,mysql_close()还将解除分配由mysql指向的连接句柄。
返回值
无。
错误
无。
实现代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include"mysql.h"
//define something for the connect function
//connect to localhost
#define _HOST_ "127.0.0.1"
//user of the database,not the linux
#define _USER_ "debian-sys-maint"
#define _PASSWD_ "7kEJiQ1hzUC3dpGm"
#define _DBNAME_ "mydb1"
int main(){
//1.init
MYSQL *mysql=mysql_init(NULL);
if(mysql==NULL){
printf("init err\n");
exit(1);
}
//2.real_connect
mysql=mysql_real_connect(mysql, _HOST_, _USER_,_PASSWD_,_DBNAME_,0,NULL,0);
if(mysql==NULL){
printf("connect err\n");
exit(1);
}
printf("revenger never die!!!\n");
//3.close
mysql_close(mysql);
return 0;
}
注:用户名密码通过查看/etc/mysql/debian.cnf.获取
# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host = localhost
user = debian-sys-maint
password = 7kEJiQ1hzUC3dpGm
socket = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host = localhost
user = debian-sys-maint
password = 7kEJiQ1hzUC3dpGm
socket = /var/run/mysqld/mysqld.sock
编译
gcc hello.c -I/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient -lstdc++ -ldl -lpthread -lrt
运行结果
实现——登录mysql,执行一次插入操作
mysql_query()
int mysql_query(MYSQL *mysql, const char *query)
- mysql连接句柄
- query 是一个sql
实现代码
根据数据库实际情况,选择一张表,向其中插入数据
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include"mysql.h"
//define something for the connect function
//connect to localhost
#define _HOST_ "127.0.0.1"
//user of the database,not the linux
#define _USER_ "debian-sys-maint"
#define _PASSWD_ "7kEJiQ1hzUC3dpGm"
#define _DBNAME_ "mydb1"
int main(){
//1.init
MYSQL *mysql=mysql_init(NULL);
if(mysql==NULL){
printf("init err\n");
exit(1);
}
//2.real_connect
mysql=mysql_real_connect(mysql, _HOST_, _USER_,_PASSWD_,_DBNAME_,0,NULL,0);
if(mysql==NULL){
printf("connect err\n");
exit(1);
}
printf("revenger never die!!!\n");
char rSql[256]={0};
strcpy(rSql, "insert into myclass(name) value('cnm')");
if(mysql_query(mysql, rSql)!=0){
printf("mysql_query err\n");
exit(1);
}
//3.close
mysql_close(mysql);
return 0;
}
写一个makefile,方便编译
SrcFiles=$(wildcard *.c)
TargetFiles=$(patsubst %.c,%,$(SrcFiles))
IncPath=/usr/include/mysql
LibPath=/usr/lib64/mysql
PubLib=-lmysqlclient -lstdc++ -ldl -lpthread -lrt
all:$(TargetFiles)
%:%.c
gcc -o $@ $^ -I$(IncPath) -L$(LibPath) $(PubLib)
clean:
-rm -f $(TargetFiles)
其中:
wildcard——Makefile中wildcard的介绍 - haoxing990 - 博客园
makefile中的notdir,wildcard和patsubst - Biiigfish - 博客园
运行结果
实现——实现查询功能
- 第一步:登录mysql
- 第二步:执行mysql_query
- 第三步:显示结果集
显示结果集的函数——mysql_store_result()
MYSQL_RES *mysql_store_result(MYSQL *mysql)
- mysql 连接句柄
- 返回 MYSQL_RES*结构指针
描述
对于成功检索了数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE等),必须调用mysql_store_result()或mysql_use_result() 。
对于其他查询,不需要调用mysql_store_result()或mysql_use_result(),但是如果在任何情况下均调用了mysql_store_result(),它也不会导致任何伤害或性能降低。通过检查mysql_store_result()是否返回0,可检测查询是否没有结果集(以后会更多)。
如果希望了解查询是否应返回结果集,可使用mysql_field_count()进行检查。
mysql_store_result()将查询的全部结果读取到客户端,分配1个MYSQL_RES结构,并将结果置于该结构中。
如果查询未返回结果集,mysql_store_result()将返回Null指针(例如,如果查询是INSERT语句)。
如果读取结果集失败,mysql_store_result()还会返回Null指针。通过检查mysql_error()是否返回非空字符串,mysql_errno()是否返回非0值,或mysql_field_count()是否返回0,可以检查是否出现了错误。
如果未返回行,将返回空的结果集。(空结果集设置不同于作为返回值的空指针)。
一旦调用了mysql_store_result()并获得了不是Null指针的结果,可调用mysql_num_rows()来找出结果集中的行数。
可以调用mysql_fetch_row()来获取结果集中的行,或调用mysql_row_seek()和mysql_row_tell()来获取或设置结果集中的当前行位置。
一旦完成了对结果集的操作,必须调用mysql_free_result()。
mysql_free_result()
void mysql_free_result(MYSQL_RES *result)
描述
释放由mysql_store_result()、mysql_use_result()、mysql_list_dbs()等为结果集分配的内存。完成对结果集的操作后,必须调用mysql_free_result()释放结果集使用的内存。
释放完成后,不要尝试访问结果集。
返回值
无。
错误
无。
mysql_fetch_row()——获取值
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
- 在mysql.h中查看MYSQL_ROW的定义——typedef char **MYSQL_ROW;
描述
检索结果集的下一行。在mysql_store_result()之后使用时,如果没有要检索的行,mysql_fetch_row()返回NULL。在mysql_use_result()之后使用时,如果没有要检索的行或出现了错误,mysql_fetch_row()返回NULL。
行内值的数目由mysql_num_fields(result)给出。如果行中保存了调用mysql_fetch_row()返回的值,将按照row[0]到row[mysql_num_fields(result)-1],访问这些值的指针。行中的NULL值由NULL指针指明。
可以通过调用mysql_fetch_lengths()来获得行中字段值的长度。对于空字段以及包含NULL的字段,长度为0。通过检查字段值的指针,能够区分它们。如果指针为NULL,字段为NULL,否则字段为空。
返回值
下一行的MYSQL_ROW结构。如果没有更多要检索的行或出现了错误,返回NULL。
示例:
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;
//获取字段个数
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
unsigned long *lengths;
//获取字段结果的长度
lengths = mysql_fetch_lengths(result);
for(i = 0; i < num_fields; i++)
{
printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
}
printf("\n");
}
实现代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include"mysql.h"
//define something for the connect function
//connect to localhost
#define _HOST_ "127.0.0.1"
//user of the database,not the linux
#define _USER_ "debian-sys-maint"
#define _PASSWD_ "7kEJiQ1hzUC3dpGm"
#define _DBNAME_ "mydb1"
int main(){
//1.init
MYSQL *mysql=mysql_init(NULL);
if(mysql==NULL){
printf("init err\n");
exit(1);
}
//2.real_connect
mysql=mysql_real_connect(mysql, _HOST_, _USER_,_PASSWD_,_DBNAME_,0,NULL,0);
if(mysql==NULL){
printf("connect err\n");
exit(1);
}
printf("revenger never die!!!\n");
char rSql[256]={0};
strcpy(rSql, "select * from myclass");
if(mysql_query(mysql, rSql)!=0){
printf("mysql_query err\n");
exit(1);
}
//get the reault
MYSQL_RES *result = mysql_store_result(mysql);
MYSQL_ROW row;
if(result !=NULL){
//PRINT THE RESULT line by line
while((row=mysql_fetch_row(result))!=NULL){
for(int i=0; i<2; i++){
printf("%s\t",row[i]);
}
printf("\n");
}
}
//free the MYSQL_RES
mysql_free_result(result);
//3.close
mysql_close(mysql);
return 0;
}
mysql_fetch_fields()——获取表头
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)
描述
对于结果集,返回所有MYSQL_FIELD结构的数组。每个结构提供了结果集中1列的字段定义。
返回值
关于结果集所有列的MYSQL_FIELD结构的数组。
错误
无。
示例:
unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *fields;
num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
for(i = 0; i < num_fields; i++)
{
printf("Field %u is %s\n", i, fields[i].name);
}
代码升级
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "mysql.h"
//define something for the connect function
//connect to localhost
#define _HOST_ "127.0.0.1"
//user of the database,not the linux
#define _USER_ "debian-sys-maint"
#define _PASSWD_ "7kEJiQ1hzUC3dpGm"
#define _DBNAME_ "mydb1"
void show_result(MYSQL_RES * result)
{
//打印表头
unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *fields;
num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
for(i = 0; i < num_fields; i++)
{
printf("%s\t", fields[i].name);
}
printf("\n+-------+--------+-----------+------+------------+------+------+--------+\n");
MYSQL_ROW row;
num_fields = mysql_num_fields(result);//取字段个数
while ((row = mysql_fetch_row(result)))//循环取一行
{
for(i = 0; i < num_fields; i++)
{
printf("%s\t", row[i] ? row[i] : "NULL");
}
printf("\n");
}
}
int main()
{
//1.init
MYSQL *mysql = mysql_init(NULL);
if (mysql == NULL) {
printf("init err\n");
exit(1);
}
//2.real_connect
mysql = mysql_real_connect(mysql, _HOST_, _USER_, _PASSWD_, _DBNAME_, 0, NULL, 0);
if (mysql == NULL) {
printf("connect err\n");
exit(1);
}
printf("revenger never die!!!\n");
char rSql[256] = { 0 };
strcpy(rSql, "select * from myclass");
if (mysql_query(mysql, rSql) != 0) {
printf("mysql_query err\n");
exit(1);
}
//取回结果集
int i=0;
MYSQL_RES * result = mysql_store_result(mysql);
MYSQL_ROW row;
if(result != NULL){
//需要打印结果集
show_result(result);
mysql_free_result(result);//释放结果集
}
//3. close
mysql_close(mysql);
return 0;
}