mysql(五)(mysql多表查询、mysql api的调用)

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)

其中:

makefile

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;
}


猜你喜欢

转载自blog.csdn.net/qq_29996285/article/details/88426741