Databases

发布时间 2023-10-22 16:18:26作者: 無敗の草

Fundamentals of MySQL

  1. MySQL:是用于管理文件的一个软件

    1. 服务端软件:socket服务端、本地文件操作、解析指令(SQL语句)

    2. 客户端软件(各种各样):socket客户端、发送指令、解析指令(SQL语句)

  2. ps:DBMS数据库管理系统、SQL语句

  3. 技能:安装 服务端和客户端

  4. 学习SQL语句规则;指示服务端做任意操作

Install

  1. 安装SQL:https://dev.mysql.com/downloads/mysql/。MySQL分为:mysql.exe (客户端)、mysqld.exe (服务端)。

  2. 给MySQLServer添加环境变量PATH=path\mysql-8.0.11-winx64\bin;

  3. 在“mysql-8.0.11-winx64”目录下创建名为“my.ini”的文件。

     
     
  4. 以管理员身份打开cmd、输入“mysqld --initialize --console”。记得root@localhost: rI5rvf5x5G,其中rI5rvf5x5G,E”就是初始密码(不含首位空格)。

  5. 为了不每次使用都打开mysqldServer可以添加系统服务。

    1. 在服务器路径后面加上--install就可以在后台创建mysqld服务端了

    2. 在服务器路径后面加上--remove就可以删除后台服务mysqld服务端了

    3. 执行net start MySQL命令就可以启动服务

    4. 执行net stop MySQL命令就可以停止服务

  6. 在终端写入mysql -u root -p,就是登录mysql了。

  7. 修改密码ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码';

用户和权限

  1. Add Users

     
     
  2. 用户管理

     
     
  3. 权限管理

     
     
  4. 权限

     
     
  5. 用户ip

     
     

数据库和表

  1. 数据库

     
     
  2.  
     

数据类型

 
 

外键与练习

  1. 外键

     
     
  2. 练习

     
     

基本认识

 
 

数据行操作

 
 

练习题

 
 

MySQL Advanced

pymysql

  1. python模块:对数据库进行操作(sql语句)

  2. pip3 install pymysql -i https://pypi.douban.com/simple

  3. 打开和关闭

     
     
  4. 防止mysql注入

     
     
  5. 插入要加的命令

    user = liyonghao 
    pwd = 222
    conn = pymysql.connect(host="localhost",   
    user="root",password="1451964253",
    database="db1")	
    cursor = conn.cursor()	
    sql = "insert into userinfo(user,password) values('%s','%s')" 
    cursor.execute(sql,name,pwd) 
    conn.commit()  										# 进行提交如果没有就无法最表做操作
    # result = cursor.fetchone()只有在查的时候用  
    cursor.close()    									# 关闭游标
    conn.close()    									# 关闭链接
  6. 批量插入

    conn = pymysql.connect(host="localhost",   
    user="root",password="1451964253",
    database="db1")	
    cursor = conn.cursor()	
    sql = "insert into userinfo(user,password) values('%s','%s')"
    # 命令返回给r,r就代表受影响的行数,现在受影响的行数为二
    r = cursor.executemany(sql,[('nihao','ss'),('tahao','33')])
    # 只要在列表中包含元祖再把命令改成executemany就可以了
    conn.commit()  										# 进行提交如果没有就无法修改
    # result = cursor.fetchone()只有在查的时候用  
    cursor.close()
    conn.close()
  7. 查的操作

    user = input ("username:")
    pwd = input ("password:")
    conn = pymysql.connect(host="localhost",user="root",    password="1451964253",database="db1")
    cursor = conn.cursor()	
    # cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  他默认是等于null的,在括号中加上这条命令就可以,以字典的方式显示	
    sql = "select* from userinfo where name='%s' and password='%s'" %(user,pwd)
    cursor.execute(sql)   
    # cursor.scroll(1,mode="relative")
    # 相对当前位置移动,再当前位置移动一位
    # cursor.scroll(2,mode="absolute")
    # 相对绝对位置移动,直接移动到第二条的位置
    result = cursor.fetchone()    
    # result = cursor.fetchmany(2)
    # 以指定为数去取指定的几条记录
    # result = cursor.fetchall()
    # 拿到所有记录
    # 默认拿到的是元祖
    cursor.close()  
    conn.close()  
  8. 新插入数据的自增id

    user = liyonghao 
    pwd = 222
    conn = pymysql.connect(host="localhost",   
    user="root",password="1451964253",
    database="db1")	
    cursor = conn.cursor()	
    sql = "insert into userinfo(user,password) values('%s','%s')" 
    cursor.execute(sql,name,pwd) 
    print(cursor.lastrowid)# 那到你插入了数据的自增的id,插入多条数据只能拿到最后一条数据id
    conn.commit()  
    cursor.close() 
    conn.close() 
  9. 练习(mysql)

    -- create database db2 default charset utf8;
    -- use db2
    -- CREATE TABLE competence ( 
    -- cid BIGINT auto_increment PRIMARY KEY,
    -- cname VARCHAR ( 20 ) ) engine=innodb 
    -- DEFAULT charset = utf8;
    -- constraint fk_course_teacher foreign key (tearch_id) references teacher(tid)
    -- insert into competence(cname) values("订单管理"),("用户管理"),("菜单管理"),("权限分配"),("Bug管理");
    -- CREATE TABLE usertable( 
    -- uid BIGINT auto_increment PRIMARY KEY,
    -- username VARCHAR ( 10 ),
    -- competence_id bigint 
    -- ) engine=innodb 
    -- DEFAULT charset = utf8;
    -- CREATE TABLE competenceuser( 
    -- cuid BIGINT auto_increment PRIMARY KEY,
    -- user_id bigint,
    -- constraint competence_user1 foreign key (user_id) references usertable(uid),
    -- competence_id bigint,
    -- constraint competence_user2 foreign key (competence_id) references competence(cid)
    -- ) engine=innodb 
    -- DEFAULT charset = utf8;
    -- insert into usertable(username,passwordn) values ("1451964253",123456),("1536945995",12345),("18993538183",1234),("xiaogan",123),("xiaoming ",12);
    -- insert into competenceuser(user_id,competence_id) values (1,1),(1,2),(2,1),(4,5),(2,2),(2,5),(3,1),(2,2),(2,3)
  10. mysql(python)

    import pymysql   
    
    user = input ("username:")
    pwd = input ("password:")
    conn = pymysql.connect(host="localhost",user="root",password="1451964253",database="db2")
    cursor = conn.cursor()
    
    def mysqlfunction (sql,*arge):
        cursor.execute(sql,[*arge])
        return cursor.fetchall()
    
    sql = "select uid from usertable where username=%s and passwordn=%s"
    result = mysqlfunction(sql,user,pwd)
    if result:
        print("登录成功")
        sql = "select competence.cname from competenceuser left join competence on competenceuser.competence_id = competence.cid where user_id=%s"
        competence= [i[0] for i in mysqlfunction(sql,result)]
        print("%s用户的所有权限:%s"%(user,",".join(competence)))
    else:
        print("登录失败")
        
    cursor.close()   
    conn.close()
  11. 再补

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
      
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
    # 创建游标
    cursor = conn.cursor()
      
    # 执行SQL,并返回收影响行数
    effect_row = cursor.execute("update hosts set host = '1.1.1.2'")
      
    # 执行SQL,并返回受影响行数
    #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,))
      
    # 执行SQL,并返回受影响行数
    #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)])
      
      
    # 提交,不然无法保存新建或者修改的数据
    conn.commit()
      
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 获取最新自增ID
    new_id = cursor.lastrowid
    注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:
    
    cursor.scroll(1,mode='relative')  # 相对当前位置移动
    cursor.scroll(2,mode='absolute') # 相对绝对位置移动

视图和触发器

  1. 视图是一张物理表的映射,它只存在于内存,他无法自己修个数据,必须在屋里表中修个

    create view "name" as sql "command";						# 创建
    alter view "name" as sql "command";							# 修改
    drop view "name";											# 删除
    
    create view v1 as select * from coret where sid > 10;		# 示例
  2. 触发器

    # 创建
    # 创建触发器before insert插入之前做操作,ROM each row 你在tb1插一条数据就会执行一次下面的语句组
    create trigger 触发器名称 before insert on tb1 ROM each row				
    begin
    	。。。。
    end
    # 创建触发器,before insert插入之后做操作,ROM each row 你在tb1插一条数据就会执行一次下面的语句组
    create trigger 触发器名称 after insert on tb1 ROM each row				
    begin
    	。。。。
    end
    # before insert bi fou | ying se te    插入前
    # after insert a fu te | ying se te    插入后
    # before delete bi fou|di lei te       删除前
    # after delete a fu te | di lei te     删除后
    # berore update bi fou | a buo dei te  更新前
    # after update a fu te | a buo dei te  更新后
    
    
    # 修改终止符
    delimiter <符号>     											# 你要修改的符号
    delimiter //
    
    # 删除触发器
    drop trigger 触发器名称;
    
    # 获得数据
    nen															# 获得新数据,比如插入一条数据,nen.xx得到插入的某一个列值。
    old															# 获得老数据,比如你要删除一条数据加上old就可以得到你要删的那行数据的某个值。用法一样
    # 示例
    create trigger t1 before insert on xx for each row
    begin 
      insert into teacher(tname) values (new.name)
    end

函数

  1. 使用函数select "function"

  2. 内置函数

    CHAR_LENGTH(str)   #计算字符串的长度,CHAR_LENGTH()返回值为5
    LENGTH()    #对于一个包含五个二字节字符集, 返回值为 10, 
    CONCAT(str1,str2,...)#字符串拼接,参数中有null就返回null。
        CONCAT_WS(separator,str1,str2,...)
            字符串拼接(自定义连接符)
            CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。
    
        CONV(N,from_base,to_base)
            进制转换
            例如:
                SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示
    
        FORMAT(X,D)
            将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若  D 为 0, 则返回结果不带有小数点,或不含小数部分。
            例如:
                SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
        INSERT(str,pos,len,newstr)
            在str的指定位置插入字符串
                pos:要替换位置其实位置
                len:替换的长度
                newstr:新字符串
            特别的:
                如果pos超过原字符串长度,则返回原字符串
                如果len超过原字符串长度,则由新字符串完全替换
        INSTR(str,substr)
            返回字符串 str 中子字符串的第一个出现位置。
    
        LEFT(str,len)
            返回字符串str 从开始的len位置的子序列字符。
    
        LOWER(str)
            变小写
    
        UPPER(str)
            变大写
    
        LTRIM(str)
            返回字符串 str ,其引导空格字符被删除。
        RTRIM(str)
            返回字符串 str ,结尾空格字符被删去。
        SUBSTRING(str,pos,len)
            获取字符串子序列
    
        LOCATE(substr,str,pos)
            获取子序列索引位置
    
        REPEAT(str,count)
            返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
            若 count <= 0,则返回一个空字符串。
            若str 或 count 为 NULL,则返回 NULL 。
        REPLACE(str,from_str,to_str)
            返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
        REVERSE(str)
            返回字符串 str ,顺序和字符顺序相反。
        RIGHT(str,len)
            从字符串str 开始,返回从后边开始len个字符组成的子序列
    
        SPACE(N)
            返回一个由N空格组成的字符串。
    
        SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
            不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。
    
            mysql> SELECT SUBSTRING('Quadratically',5);
                -> 'ratically'
    
            mysql> SELECT SUBSTRING('foobarbar' FROM 4);
                -> 'barbar'
    
            mysql> SELECT SUBSTRING('Quadratically',5,6);
                -> 'ratica'
    
            mysql> SELECT SUBSTRING('Sakila', -3);
                -> 'ila'
    
            mysql> SELECT SUBSTRING('Sakila', -5, 3);
                -> 'aki'
    
            mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
                -> 'ki'
    
        TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
            返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。
    
            mysql> SELECT TRIM('  bar   ');
                    -> 'bar'
    
            mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
                    -> 'barxxx'
    
            mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
                    -> 'bar'
    
            mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
                    -> 'barx'
    
    部分内置函数
    DATE_FORMAT(段名,"%Y")    #时间格式化,取想要的值
  3. 自定义函数

    delimiter \\				 					# 定义终止程序符号为\\
    create function f1(			  					# 定义函数传两个值都是数值型
    	i1 int,
    	i2 int)
    returns int					 					# 定义返回值为数值型
    begin						 					# 开始执行体
    	declare num int default 0; 					# 定义变量为数值型初始值为0
    	set num = i1 + i2;		  					# 给变量赋值
    	return(num);			  					# 返回变量
    end \\						 					# 结束定义的执行体
    delimiter ;					 					# 定义终止程序符号为;
    # 警告:函数中不能写select * from tb;
    
    drop function "func_name";						# 删除函数

储存过程

  1. 过程文件就是在mysql上的一个别名 => 一坨sql代码,用于替代程序员写sql语句。

  2. 创建过程

    delimiter //
    create procedure p1()
    begin
    	select * from student;
    	insert into teacher(tname) values("ct");
    end //
    delimiter ;
    
    call 过程名();									# mysql里面
  3. pymysql里面调用

    conn = pymysql.connect(host="localhost",user="root",password="1451964253",database="db1",charset="utf8") # 在这里需要加上charset="utf8",不然中文显示不了 
    cursor = conn.cursor()  
    cursor.callproc("p1")    # 如果要调用存储过程的话,就要加上callproc(xx)
    idconn.commit()  
    cursor.close() 
    conn.close() 
  4. 传参

    #传参数的存储过程,定义参数必须要加(in,out,inout)
    in  ying    #传入
    create procedure p3(
    	in n1 int,
        in n2 int
    )
    begin 
    	select * from student where sid>n1;
    end
    
    call p3(12,3)
    cursor.callproc("p3",(12,2))
    ###############################
    out ao te    #传出 内部的一个值传到外部,内部也可以用
    
    create procedure p3(
    	in n1 int,
        out n2 int
    )
    begin 
    	set n2 = 1234123;
    	select * from student where sid>n1;
    end
    set @v1 = 0;    #就和Python中的全局变量一样
    call p3(12,@v1)
    ########################################
    #pymysql
    conn = pymysql.connect(host="localhost",user="root",password="1451964253",database="db1",charset="utf8") 
    cursor = conn.cursor()  
    cursor.callproc("p3",(12,2))    #
    result = cursor.fetchall()
    print(result)
    
    cursor.execute("select @_p3_0,@_p3_1")    #@_p3_0代表第一个参数,@_p3_1代表第二个
    result1 = cursor.fetchall()
    print(result1)
    cursor.close() 
    conn.close() 
    ##################################
    #可以外传也可以传入
    inout ying ao te
  5. 为什么有结果集又有out伪造的返回值?uot用于标识存储过程的执行结果

  6. 事务

    delimiter \\
        create PROCEDURE p1(
            OUT p_return_code tinyint
        )
        BEGIN 
            DECLARE exit handler for sqlexception  #出现异常自动执行这块代码
            BEGIN 
                -- ERROR 
                set p_return_code = 1; 
                rollback;     #ru bai ke 会到原始状态
            END; 
                            
            DECLARE exit handler for sqlwarning 
            BEGIN 
                -- WARNING 
                set p_return_code = 2; 
                rollback; 
            END; 
                             
            START TRANSACTION;     #si da te|chuan si kei sheng 开始事务
                 DELETE from tb1;
                 insert into tb2(name)values('seven');
            COMMIT;     #kan mi te 提交
                             
            -- SUCCESS     sai te 
            set p_return_code = 0; 
                             
            END\\
    delimiter ;
  7. 游标

    delimiter //
    create procedure p6()
    begin
    #定义声明
    	declare row_id int;   
    	declare row_num int;
    	declare done int default FALSE;#done=false
    	#my_cursor=游标
    	declare temp int;
    	declare my_cursor cursor for select id,num from student;
        #判断表没有织的时候,这样写游标自动判断是否有数据。
    	declare continue handler for not found set done = TRUE;   
    	open my_cursor;    #打开游标
    		xxoo:loop    #开始循环
    			#获取my_cursor中的一条数据赋给变量
    			fetch my_cursor into row_id,row_num;
    			if done then   #如果done = then
    				leave xxoo;    #跳出循环
    			end if;
    			set temp = row_id + row_num;
    			insert into teacher(num) values(temp);
    		end loop xxoo;    #结束循环
    	close my_cursor;    #关闭游标
    end //
    delimiter ;
    
    call p6();
  8. 动态执行sql(防sql注入)

    delimiter //
    create procedure p7 (
    	in nid int 
    )
    begin
    	#1.预检测某个东西sql语句合法性
    	#2.sql = 格式化 tpl + arg
    	#3.执行sql语句
    	set @nid = nid;
    	prepare prod from "select * from student where id>?"; #pu rui pei er 准备 
    	execute prod using @nid;
    	#yi kei you te 执行,you rei,@arg 替换?号,这里的arg不能直接加,需要重新的以才能加
    	deallocate prepare prod;
    	#dai ao lao kei te ,pu rui pai,执行sql语句
    end //
    delimiter ;

索引

  1. 链接别人的mysqlamysql -u root -h 10.10.100.3 -p

  2. 作用:约束、加速查找。

  3. 索引

    1. 普通索引:加速查找

    2. 主键索引:加速查找、不能为空、不能重复

    3. 唯一索引:加速查找、不能重复

    4. 联合索引(多列):联合主键索引、联合唯一索引、联合普通索引

  4. hash索引

    1. hash索引是建立一个索引表,把数据转化成指定的个是储存,后面加上硬盘地址,hash保存是没有顺序的。你查文件时它会把硬盘地址直接给你。范围查找速度会慢

  5. btree索引

    1. btree是以中值分为金字塔排的,小于中值左边,大于中值右边,依次往下排。

    2. 例如:100*2=50,小于50左,大于50右。50 *2=25,小于25左,大于25右。

    3. 寻找次数 2**10,寻找次数10次

  6. 建立索引

    1. 额外的文件保存特殊的数据结构

索引使用

1.普通索引

  1. 普通索引仅有一个功能:加速查询

  2. 创建表 + 索引

    create table in1(
        nid int not null auto_increment primary key,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text,
        index ix_name (name)
    )
  3. 使用

    create index "name" on "table_name(field)"							# 创建索引
    drop index "name" on "table_name"									# 删除索引
    show index from "table_name";										# 查看索引
    create index ix_extra on in1(extra(32));							
  4. 注意:对于创建索引时如果是blob和text 类型,必须指定length

2.唯一索引

  1. 唯一索引有两个功能:加速查找 和 唯一约束(可含null)

  2. 创建表 + 唯一索引

    create table in1(
        nid int not null auto_increment primary key,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text,
        unique ix_name (name)
    )
  3. 使用

    create unique index "name" on "table_name(field)"					# 创建索引
    drop unique index "name" on "table_name"							# 删除索引						

3.组合索引

  1. 组合索引是将n个列组合成一个索引,其应用场景为:频繁的同时使用n列来进行查询。例如:where n2 = "alex" and n3 = 666。

  2. 创建表

    create table in3(
        nid int not null auto_increment primary key,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text
    )
  3. 使用

    create index "name" on "table_name(field,field)"					# 创建索引
    drop index "name" on "table_name"									# 删除索引						
  4. 注意:对于同时搜索n个条件时,组合索引的性能好与多个单一索引合并。

  5. 组合索引遵循最左前缀匹配

    create index ix_name_email on wserinfo3(name,email,ex)
    select * from userinfo3 where name="alex" 
    select * from userinfo3 where name="alex"and email="a" 
    select * from userinfo3 where email="xxx"
    # 1和2可以三不可以,因为三没有遵循最左前缀匹配,最左前缀是name开头,name没有开头就不行
  6. 索引合并没有组合索引效率高

  7. 索引组合是把有索引的数据行组合进行索引

4.主键索引

  1. 创建表+创建主键

    create table in1(
        nid int not null auto_increment primary key,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text,
        index ix_name (name)
    )
    
    OR
    
    create table in1(
        nid int not null auto_increment,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text,
        primary key(ni1),
        index ix_name (name)
    )
  2. 使用

    alter table "tableName" add primary key(field);						# 创建主键
    alter table "tableName" drop primary key;							# 删除主键
    alter table "tableName"  modify "field" int, drop primary key;

5.覆盖索引

  1. 名词:不是真实的索引

  2. 覆盖索引就是创建一个email索引,显示时只显示email它就不会去数据表里找,在索引文件中直接获取数据select email from tb1 where email = "alex@qq.com111"

6.索引合并

  1. 名词:不存在,把多个单列索引合并使用select * from tb1 where a1 = "1" and a2 = "2"

正确使用索引

  • 数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。 即使建立索引,索引也不会生效:

    like '%xx'
        select * from tb1 where name like '%cn';
     使用函数
        select * from tb1 where reverse(name) = 'wupeiqi';
     or
        select * from tb1 where nid = 1 or email = 'seven@live.com';
        特别的:当or条件中有未建立索引的列才失效,以下会走索引
                select * from tb1 where nid = 1 or name = 'seven';
                select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
     类型不一致
        如果列是字符串类型,传入条件是必须用引号引起来,不然...
        select * from tb1 where name = 999;
     !=
        select * from tb1 where name != 'alex'
        特别的:如果是主键,则还是会走索引
            select * from tb1 where nid != 123
     >
        select * from tb1 where name > 'alex'
        特别的:如果是主键或索引是整数类型,则还是会走索引
            select * from tb1 where nid > 123
            select * from tb1 where num > 123
     order by
        select email from tb1 order by name desc;
        当根据索引排序时候,选择的映射如果不是索引,则不走索引
        特别的:如果对主键排序,则还是走索引:
            select * from tb1 order by nid desc;
     
     组合索引最左前缀
        如果组合索引为:(name,email)
        name and email       -- 使用索引
        name                 -- 使用索引
        email                -- 不使用索引

其他注意事项

避免使用select *
count(1)或count(列) 代替 count(*)
创建表时尽量时 char 代替 varchar
表的字段顺序固定长度的字段优先
组合索引代替多个单列索引(经常使用多个条件查询时)
尽量使用短索引
使用连接(JOIN)来代替子查询(Sub-Queries)
连表时注意条件类型需一致
索引散列值(重复少)不适合建索引,例:性别不适合

其他

条件语句

delimiter \\
CREATE PROCEDURE proc_if ()
BEGIN
    
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END\\
delimiter ;

循环语句

  1. while循环

    delimiter \\
    CREATE PROCEDURE proc_while ()
    BEGIN
    
        DECLARE num INT ;
        SET num = 0 ;
        WHILE num < 10 DO
            SELECT
                num ;
            SET num = num + 1 ;
        END WHILE ;
    
    END\\
    delimiter ;
  2. repeat循环

    delimiter \\
    CREATE PROCEDURE proc_repeat ()
    BEGIN
    
        DECLARE i INT ;
        SET i = 0 ;
        repeat
            select i;
            set i = i + 1;
            until i >= 5
        end repeat;
    
    END\\
    delimiter ;
  3. loop

    BEGIN
        
        declare i int default 0;
        loop_label: loop
            
            set i=i+1;
            if i<8 then
                iterate loop_label;
            end if;
            if i>=10 then
                leave loop_label;
            end if;
            select i;
        end loop loop_label;
    
    END

动态执行sql语句

delimiter \\
DROP PROCEDURE IF EXISTS proc_sql \\
CREATE PROCEDURE proc_sql ()
BEGIN
    declare p1 int;
    set p1 = 11;
    set @p1 = p1;

    PREPARE prod FROM 'select * from tb2 where nid > ?';
    EXECUTE prod USING @p1;
    DEALLOCATE prepare prod; 

END\\
delimiter ;

时间

  1. 大概判断一条sql命令所需的时间,创建预测,explain mysql命令。

  2. type = all 是全表扫描,id不是唯一表示,只是代指这个表,type = ref是走了索引的

    id
    查询顺序标识
    如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
        +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
        +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
        |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
        +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
    特别的:如果使用union连接气值可能为null
    
    select_type
    查询类型
        SIMPLE          简单查询
        PRIMARY         最外层查询
        SUBQUERY        映射为子查询
        DERIVED         子查询
        UNION           联合
        UNION RESULT    使用联合的结果
    
    table
    	正在访问的表名
  3. type

      type
          查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
              ALL             全表扫描,对于数据表从头到尾找一遍
                              select * from tb1;
                              特别的:如果有limit限制,则找到之后就不在继续向下扫描
                                     select * from tb1 where email = 'seven@live.com'
                                     select * from tb1 where email = 'seven@live.com' limit 1;
                                     select * from tb1 where email = 'seven@live.com' limit 1,10;#显示前十条
                                     虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。
      
              INDEX           全索引扫描,对索引从头到尾找一遍
                              select nid from tb1;
      
              RANGE          对索引列进行范围查找
                              select *  from tb1 where name < 'alex';
                              PS:
                                  between and
                                  in
                                  >   >=  <   <=  操作
                                  注意:!= 和 > 符号
              INDEX_MERGE     合并索引,使用多个单列索引搜索
                              select *  from tb1 where name = 'alex' or nid in (11,22,33);
      
              REF             根据索引查找一个或多个值
                              select *  from tb1 where name = 'seven';
      
              EQ_REF          连接时使用primary key 或 unique类型
                              select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
              CONST           常量
                              表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
                              select nid from tb1 where nid = 2 ;
      
              SYSTEM          系统
                              表仅有一行(=系统表)。这是const联接类型的一个特例。
                              select * from (select nid from tb1 where nid = 1) as A;
      possible_keys
          可能使用的索引
      
      key
          真实使用的
      
      key_len
          MySQL中使用索引字节长度
      
      rows
          mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值
      
      extra
          该列包含MySQL解决查询的详细信息
          “Using index”
              此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
          “Using where”
              这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
          “Using temporary”
              这意味着mysql在对查询结果排序时会使用一个临时表。
          “Using filesort”
              这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
          “Range checked for each record(index map: N)”
              这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
  4. 慢日志查询,需要:条件,路径

    # 配置MySQL自动记录慢日志
    
    # 内存中配置
    slow_query_log = OFF|ON										# 是否开启慢日志记录
    long_query_time = 2											# 时间限制,超过此时间,则记录
    slow_query_log_file = /usr/slow.log							# 日志文件
    log_queries_not_using_indexes = OFF							# 为使用索引的搜索是否记录
    
    *注:查看当前配置信息:*
         *show variables like '%query%'*
       *修改当前配置:*
        *set global 变量名 = 值*
    配置文件中配置
    	mysqld --defaults-file="D:my.conf"						# 启动配置文件
    	my.conf内容:						 					  # 配置文件
    		slow_query_log = on
    		slow_query_log_file = D:/...
    #你可以把配置文件放在其他位置需要写这条命令my.ini
    	datadir = 配置文件路径
    	#然后再打开就可以应用这个配置文件了
    	#注意:修改配置文件之后,需要重启服务
    		#现将原本的配置备份,防止修改的配置文件出现问题,修改不回来
  5. 查看MySQL慢日志

    mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log
    """
        --verbose 		版本
        --debug   		调试
        --help    		帮助
        -v      		版本
        -d      		调试模式
        -s ORDER   		排序方式
    what to sort by (al, at, ar, c, l, r, t), 'at' is default
    al: average lock time
    ar: average rows sent
    at: average query time
    c: count
    l: lock time
    r: rows sent
    t: query time
        -r      		反转顺序,默认文件倒序拍。reverse the sort order (largest last instead of first)
        -t NUM    		显示前N条just show the top n queries
        -a      		不要将SQL中数字转换成N,字符串转换成S。don't abstract all numbers to N and strings to 'S'
        -n NUM    		abstract numbers with at least n digits within names
        -g PATTERN  	正则匹配;grep: only consider stmts that include this string
        -h HOSTNAME 	mysql机器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
    default is '*', i.e. match all
        -i NAME   		name of server instance (if using mysql.server startup script)
        -l      		总时间中不减去锁定时间;don't subtract lock time from total time
    """

分页

  1. 方案:

    1. 记录当前页的最大值和最小值id

    2. 往下翻:

      select*from yonghu > 124(得到的最大id) limit 10(往下十条数据)
      在多个页面中翻找如11,往14上找就可以用这个代码
      
      select * from user where id in(
      	select id from (select id from user where id > max_id limit 30 ) as n order by n,id desc limit 10
      )
    3. 往上翻:

      select*from yonghu < 124(得到的最小id) order by id desc(从大到小排序就可以拿到上面的10条数据) limit 10(往下十条数据)
      在多个页面中翻找如11,往14上找就可以用这个代码
      
      select * from user where id in(
      	select id from (select id from user where id < max_id limit 30 ) as n order by n,id desc limit 10
      )
    4. 注意:id不连续,所以无法直接使用id进行范围查找

ORM框架

  1. SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作pip3 install SQLAlchemy

  2. 作用:提供简单的规则、自动转换成sql语句。

  3. 两类ORM框架

    1. DB first:手动创建数据库以及表然后ORM框架和自动生成类

    2. code first:手动创建类和数据库然后ORM框架和自动生成表

  4. 功能

    1. 创建数据库表:连接数据库(非做的SQLAlchemy,是做的pymysql,mysqldb,)、类转换成sql语句。

    2. 工作流程

      1. SQLAlchemy ORM:Object Relatlonal Mapper(ORM) #可以看作类、类和2.1,2.2配合起来将其转换为sql语句。

      2. SQLAlchemy Core

        1. Schema/types

        2. SQL Expression Language

        3. Engine #引擎(配置文件会给引擎):Connection Pooling #连接池(保持多少个连接)、Diaiect #选择(选择你要连接pymysql,mysqldb......)。

      3. DBAPI 代指连接(pymysql,mysqlDB,SQL,Oracle...)

基本操作

  1. 增(做操作的代表行)

    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    class UserType(Base):
        __tablename__="usertype"
        id = Column(Integer,primary_key=True,autoincrement=True)
        title = Column(String(32),nullable=True,index=True)
    
    engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/s4day62db?charset=utf8",max_overflow=5)    #连接mysql数据库
    Session = sessionmaker(bind=engine)    #获取权限
    session=Session()    #获取权限
    #单个添加
    obj1=UserType(title="普通用户")    #在title中添加“普通用户”这个值
    session.add(obj1)	#将其写入
    #多个添加
    objs =[
        UserType(title="超级用户")
        UserType(title="白金用户")
        UserType(title="黑金用户")
    ]
    session.add_all(objs)
    session.commit()    #提交
    session.close()    #关闭
  2. from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    class UserType(Base):
        __tablename__="usertype"
        id = Column(Integer,primary_key=True,autoincrement=True)
        title = Column(String(32),nullable=True,index=True)
    
    engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/s4day62db?charset=utf8",max_overflow=5)    #连接mysql数据库
    Session = sessionmaker(bind=engine)    #获取权限
    session=Session()    #获取权限
    user_type_list = session.query(UserType).filter(UserType.id>2).delete()   #查到满足条件的并删除
    #.delete()    #删除
    session.commit()    #提交
    session.close()    #关闭

     

  3. from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    
    class UserType(Base):
        __tablename__="usertype"
        id = Column(Integer,primary_key=True,autoincrement=True)
        title = Column(String(32),nullable=True,index=True)
    
    engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/s4day62db?charset=utf8",max_overflow=5)    #连接mysql数据库
    Session = sessionmaker(bind=engine)    #获取权限
    session=Session()    #获取权限
    user_type_list = session.query(UserType).filter(UserType.id>0).update({title:"黑金"})    #查到小于0的id并把title修改为“黑金”
    session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False)    #字符串做操作时
    session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate")    ##数值做操作时
    #synchronize_session=False    如果要对字符串操作时必须加、
    #synchronize_session="evaluate"    对数值做操作是必须加
    session.commit()    #提交
    session.close()    #关闭

     

  4. from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    
    class UserType(Base):
        __tablename__="usertype"
        id = Column(Integer,primary_key=True,autoincrement=True)
        title = Column(String(32),nullable=True,index=True)
    
    engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/s4day62db?charset=utf8",max_overflow=5)    #连接mysql数据库
    Session = sessionmaker(bind=engine)    #获取权限
    session=Session()    #获取权限
    user_type_list = session.query(UserType(你想取那几列可以写在这如:UserType.id"只写表名相当于sql中的*号")).all()   #查询usertype表中的所有记录
    #.all()    是全部
    #.filter(UserType.id>2)    是过滤和sql中的where一样
    print(session.query(UserType))    #可以看到sql代码
    for row in user_type_list:	
        print(row.id,row.title)
    
    session.commit()    #提交
    session.close()    #关闭
  5. 其他

    #条件
    ret = session.query(user).filtr_by(name="alex").all()
    ret = session.query(user).filter(user.id>1,user.name == "eric").all()#逗号分隔开默认是and运算
    ret = session.query(user).filter(user.id.between(1,3),user.name == "eric").all()
    #.between(1,3)
    ret=session.query(user).filter(user.id.in_([1,3,4])).all()    #in_([1,2,3])就代表in
    ret=session.query(user).filter(~user.id.in_([1,3,4])).all()    #~就代表not
    ret = session.query(user).filter(user.id.in_(session.query(user.id).filter_by(name="eric"))).all()#写表达式用filter如果是参数就用filter_by,filter_by在内部就调用的是filter,拿到的是字典在内部会被转成表达式来引用
    from sqlalcheny import and_,or_#如果要用and和or需要导入一下
    ret = session.query(user).filter(and_(user.id>3,user.name == "eric")).all()
    ret = session.query(user).filter(or_(user.id>3,user.name == "eric")).all()#用什么定义就用什么运算
    ret = session.query(user).filter(or_(user.id<2),and_(user.name == "eric",user.id>3)).all()
    #通配符
    ret = session.query(user).filter(user.naem.like("e%")).all()#找到所有e开头的用户
    ret = session.query(user).filter(~user.naem.like("e%")).all()#找到所有不是e开头的用户
    #限制
    ret = session.query(user)[1:2]#这样写是切片
    #排序
    ret = session.query(user).order_by(user.name.desc()).all()
    ret = session.query(user).order_by(user.naem.desc(),user.id.asc()).all()
    #如果姓名出现了重复就用id排序
    #分组
    from sqlalchemy.sql import func  #用之前需要导入一下
    ret = session.query(user).qroup_by(user.extre).all()
    ret = session.query(
    	func.max(user.id),
    	func.sum(user.id),
    	func.min(user.id)).group_by(user.name).all()
    #所有的函数都可以用func点出来
    ret = session.query(
    	func.max(user.id),
    	func.sum(user.id),
    	func.min(user.id)).group_by(user.name).having(func.min(user.id)>2).all()
    #连表
    ret = session.query(user,usertype).filter(user.id == usertype.nid).all()
    ret = session.query(user).join(usertype)
    ret = session.query(user).join(usertype,isouter=True)#加上isouter是左连表 
    
    #组合
    q1 =session.query(user.name).filter(user.id>2)
    q2 =session.quer(favor.caption).filter(favor.nid<2)
    ret = q1.union(q2).all() #将q1和q2上下连起来,多了个去重的功能
    
    q1 =session.query(user.name).filter(user.id>2)
    q2 =session.quer(favor.caption).filter(favor.nid<2)
    ret = q1.union_all(q2).all() #将q1和q2上下连起来,不去重
    
    #临时表
    #select * from b where id in ()
    
    #select * from (select * from tb) as b
    q1 = session.query(usertype).filter(userType.id>2).subquery()
    #如果要加临时表必须加上subquery()
    result= session.query(q1).all()
    
    #select a.id,(select * from b where b.id == a.id)from a   如果要实现这种就要用到.as_scalar()#
    result = session.query(UserType.id,session.query(user).filter(user.id==UserType.id).as_scalat())
    print(result)
    #不加它.as_scalat()是select*from a加了它是(select*from a)不加是没有括号的,想要实现就必须加
    #############################################
    #1.获取用户信息以及与其关联的用户类型名称
    #第一种普通链表
    user_list = session.query(user,UserType).join(UserType,isouter=True)
    print(session)
    for row in user_list:
        print(row[0].id,row[0].name,row[0].email)
    #第二种建立了关系的
    #创建关系就不用频繁的链表了
    user_type = relationship("UserType",backref="xxoo")
    #relationship分为
    #正向操作是根据绑定了外键的那行数据找到id表中的数据
    #反向操作是根据id绑定的外键找到被绑表中的数据,只有加了backref才能使用反向操作
    #relationship写在有foreigexey类中如:
    class User(Base):
        __tablename__ = "user"
        id = Column(Integer,primary_key=True)
        name = Column(String(32),nullable=True,autoincrement=True,dafault="sf",
    index=True)
        email = Column(String(16),unique=True)
        user_type_id = Column(Integer,ForeignKey("usertype.id"))
        relationship("UserType",backref="xxoo")
    ##########################################    
    
    user_list = session.query(user)
    for row in user_list:
        print(row.name,row.id,row.user_type.title)
    #2.获取用户类型
    #第一种
    type_list = session.query(UserType)
    for row in type_list:
        print(row.id,row.title,session.query(user).filter(user.user_type_id == row.id).all())
    #第二种
    type_list = session.query(usertype)
    for row in type_list:
        print(row.id,row.title,row.xxoo)
    #注意:加了all是吧所有的数据全部取到内存中,不加的话就和一个迭代器一样,只有在循环的之后才会拿取数据

建立表

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine

class UserType(Base):
    __tablename__="usertype"
    id = Column(Integer,primary_key=True,autoincrement=True)
    title = Column(String(32),nullable=True,index=True)

class User(Base):
    __tablename__ = "user"
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=True,autoincrement=True,dafault="sf",
index=True)
    email = Column(String(16),unique=True)
    user_type_id = Column(Integer,ForeignKey("usertype.id"))
#Column代表列
#primary_key=True 建立主索引
#autoincrement=True 建立自增
#nullable=True是否可以为空
#dafault="sf"默认值
#index=True是否建立索引
#unique=True唯一索引
#foreignKey("usertype.id")外键(约束)
engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/s4day62?charset=utf-8,max_overflow=5")
Base.metadata.create_all(engine)#建立数据表
Base.metadata.drop_all(engine)#删除表

def init_db():
    Base.metadata.create_all(engine)
#找到继承了Base并创建成表    
def drop_db():
    Base.metadata.drop_all(engine)
#找到继承了Base并删除表
init_db()
drop_db()


#规定写法:用来创建联合索引
__table_args__ = (
#唯一联合索引将id和name创建索引在取个名字	
    		UniqueConstraint("id","name",name="uix_id_name"),
 #建立一个普通索引将name和email建立普通联合索引,普通索引的名字要写到前面
    Index("sdf","name","email",)
)

Visual FoxPro

VFP基础

  1. Visual FoxPro是关系型数据库管理系统的典型代表之一。其中的Visual FoxPro6.0是一个可运行于windows平台之上的32位数据库管理系统。

  2. Ctrl+F2建是“窗口”菜单中“命令窗口”命令的组合快捷键。

基础认识

  1. 数据:数据就是描述事物的符号,文字、声音、图像等都是可以是计算机的数据。

  2. 数据处理:数据处理是值对数据进行收集、存储、分类、计算、统计、检索及传输的过程。数据处理的目的是得到信息。数据处理经历了3个主要阶段:人工管理数据阶段文件系统管理数据阶段数据库系统管理数据阶段

  3. 数据库:数据库(DataBase,DB)是有组织的,可共享的想关数据的集合。

  4. 数据库管理系统:数据库管理系统(DataBase Management System,DBMS)是管理数据库的软件系统。它的主要功能是管理和维护数据。数据库管理系统按照指定的结构存储数据,使数据具有高度的独立性,不同的应用程序可以直接操作这些数据。

  5. 实体和实体集:实体是现实世界中客观存在并且可以相互区别的事物。实体集是同一类实体组成的集合。

  6. 联系的分类:现实生活中,相关的实体之间存在着某种联系。实体之间的联系可以分为三类:一对一的联系一对多的联系多对多的联系

  7. 表格:在现实生活中,人们常常使用表格来管理数据,用二维表反映事物之间的联系。二维表可以反映一对一、一对多、多对多联系。

  8. 数据类型:从现实生活中事物的三种关系,可以抽象出三种数据模型:层次模型网状模型关系模型

  9. 关系模型:关系模型是用二维表格的形式来表示实体与实体之间联系的数据模型。满足如下要求的一张二维表就称为一个关系。

    1. 表格中的每一列都是不能再细分的基本数据项。

    2. 表格中的每一列有一个名字,不同列的名字也不同。

    3. 表格中的每一列数据都是相同类型的数据。

    4. 表格中任意两行的次序可以交换。

    5. 表格中任意两列的次序可以交换。

    6. 表单中不存在完全相同的两行数据。

  10. 数据库类型:对应以上三种数据模型,有三种数据库类型:层次数据库网状数据库关系数据库。Visual FoxPro是关系数据库。

  11. 关系的基本概念

    1. 元组:在一个二维表(一个具体关系)中,水平方向的行称为元组,每一行是一个元组。元组对应存储文件中的一个具体记录。

    2. 属性:二维表中垂直方向的列称为属性,每一列有一个属性名。

    3. 域:属性的取值范围称为,即不同元组对同一个属性的取值所限定的范围。

    4. 外部关键字:如果表中的一个字段不是本表的主关键字或候选关键字,而是另一个表的主关键字或候选关键字,那么这个字段(属性)就称为外部关键字。

  12. 关系运算:专门的关系运算有选择投影联接它们主要用于查询数据的操作。visual FoxPro 关系数据库管理系统能够实现这三种基本关系运算。

    1. 选择:从关系中找出满足给定条件的元组的操作称为选择。

    2. 投影:从关系中取出若干个属性组成新的关系的操作称为投影。

    3. 联接:把两个关系中相同属性值的

  13. 执行命令

    1. Visual FoxPro的命令窗口提供了执行命令的功能。用户可以适应多种方式在命令窗口执行命令。

      # 在屏幕上当前光标的下一行显示指定的数据。
      ?[数据列表]
      ?"Hello world"    											# 显示Hello world
      clear    													# 清除所有显示的信息
      ?date()    													# 屏幕上按“月/日/年”的格式显示当前系统日期
      ?time()   													# 屏幕上按“时:分:秒”的格式显示当前系统时间
  14. Visual FoxPro 提供了三种管理数据的方式:菜单方式命令方式程序方式

  15. 基本规则

    1. 命令的基本规则:Visual FoxPro的命令一般由两部分组成。第一部分是命令动词,第二部分为子句。

      1. 动词如:use、in、alias、create、table等。

      2. 子句如:<表文件名>、[in 工作区号]、[alias 别名]等。

      3. 分隔符:分隔符通常是一个或多个空格,在命令动词与子句、子句与子句、子句的哥哥元素之间独有分隔符。

      4. 书写形式:一行只能写一条命令,但一条命令可以写在多行。如果一条命令写在多行,Visual FoxPro规定在除最后一行外的其他各行末尾均加一个分号“;”。

      5. 关键字字母的大小写等效:命令格式中的关键字可以适应大写、小写或大小写字母混合使用。

    2. 命令格式中的符号

      1. 尖括号<>:尖括号括起来的句子是必选项,使用命令是必须选择。

      2. 方括号[]:方括号括起来的句子是可选项,使用命令时可以选择也可以不选。

      3. 竖线号“|”:竖线号表示前后两任选一项,且只能选一项。

      4. 省略号"...":省略号表示可以按前项相同方式重复。

  16. 使用帮助

    1. Visual FoxPro 有一个完善的在线帮助系统,用户可以使用查看Windows帮助系统的一般方法查看Visual FoxPro 的帮助信息。

    2. 获取屏幕对象的帮助信息:Visual FoxPro 的帮助系统较详细地介绍了Visual FoxPro 的基本功能和基本操作方法。

      1. 获取帮助信息的一般方法:单击“常用”工具栏的“帮助”按钮,或选择“帮助”‘Microsoft Visual FoxPro帮助主题“命令、“帮助”“目录”命令、“帮助”“索引”命令或“帮助”“搜索”命令,都可以打开帮助窗口。

      2. 获取菜单和窗口的帮助信息:先打开菜单或窗口,再按F1建,帮助窗口就显示指定菜单或窗口的帮助内容。

      3. 获取对话框的帮助信息:查看对话框的帮助信息时,仍然需要先打开对话框,再按F1键。

    3. 获取命令和函数的帮助信息:使用命令获取帮助信息。HELP<帮助主题>

数据运算

  1. 数据和数据运算是任何数据库管理系统的基础。Visual FoxPro 提供了丰富的数据类型和运算方法。

常用的数据类型

  1. 数据类型

    1. Visual FoxPro 提供了多种数据类型,其中常见的数据类型为数值型字符型日期型逻辑型

    2. 数据类型决定数据的运算凡是和储存方式。Visual FoxPro 提供的数据类型有Character(字符型)、Currency(货币型)、Date(日期型)、DateTime(日期时间型)、Double(双精度型)、Float(浮点型)、Logical(逻辑型)、Numeric(数值型)、Integer(整形)、General(通用型)、Memo(备注型)

  2. 常量

    • 常量是指始终保持不变的量。常量用于描述现实生活中固定不变的数据,每个常量有一个数据类型。字符型数值型日期型逻辑型常量。

      1. 字符型常量(简称为字符串)由字符型数据组成。

      2. 数值型常量(简称为数字)由数值型数据组成。

      3. 日期型常量是由花括号括起来的日期型数据。它的一般格式为{^yyyy/mm/dd},yyyy表示年份、mm表示月份、dd表示日。日期默认显示格式为:mm/dd/yy。

      4. 逻辑型常量由.T..F.这两个值组成。

  3. 变量

    • 变量是其值可以发生改变的量。变量用于描述现实生活中可以发生改变的数据,Visual FoxPro 中的变量一般分为字段变量和内存变量。

      1. 字段变量是存储在数据表中的变量。

      2. 内存变量是存储在内存中的变量。

运算符

  1. Visual FoxPro 常见的运算符有算术运算符字符运算符关系运算符逻辑运算符

  2. 算术运算符

    运算符 名称 运算符 名称
    + 加法 - 减法
    * 乘法 / 除法
    ^或** 乘方 % 求余
    1. 算术运算符的优先级依次为:乘方乘与除求余加与减、。同等级运算从左到右依次运算。当表达式中有花括号时,花括号优先级最高。

  3. 字符运算符

    1. 字符运算符用于连接两个字符型数据。Visual FoxPro 的字符运算符有如下两个:原样连接运算符“+”非原样连接运算符“-”。非原样连接会把空格移到字符串尾部。

    2. 字符运算符按从左到右的顺序进行运算。

    3. 等于号比较是看开头是否一样的。

    4. $是看一个是否在另外一个里面(位置随便)

  4. 关系运算符

    运算符 名称 运算符 名称
    > 大于 >= 大于等于
    < 小于 <= 小于等于
    = 等于 == 恒等于
    <>或!=或# 不等于 $ 包含于(仅用于字符串)
    1. 关系运算符比较数据的法则

      1. 比较数值型数据是按数值大小进行比较。

      2. 比较单个字符是按照ASCLL码值的大小进行比较。

      3. 比较字符串是按从左到右的顺序依次比较每一个位置上的字符,a字符串第一个字符和b字符串第一个字符进行比较的。

      4. 比较日期型数据是按日期的先后进行比较。

  5. 逻辑运算符

    运算符 名称 运算符 名称 运算符 名称
    and or not

内存变量简介

  1. 给内存变量命名

    1. 一般不使用Visual FoxPro的关键字作为内存变量名。

    2. 因为系统内存变量名都以下划线开头,所以一般不用下划线开头为内存变量命名,以避免与系统内存变量发生重名。

    3. 内存变量名最好不要与字段变量同名。如果内存变量与字段变量同名,Visual FoxPro 优先使用同名的字段变量。

  2. 给内存变量赋值:给单个内存变量赋值。<内存变量名>=<表达式>

  3. 给多个内存变量赋值:store<表达式>to<内存变量表>,如:store “Hello world !” to t1,t2,t3

  4. 显示内存变量

    1. list|display memory [like 变量通配名] [to printer |to file 文件名]

    2. 功能

      1. list命令使用不间断的滚动方式来显示数据。display命令使用分屏显示的方式来显示数据。

      2. 选择like后只显示like中的变量,不选择将显示所有内存变量。变量通配名中可以使用通配符“?”替代一个字符,使用“*”可以代替一个或多个字符。

      3. 选择“to printer” ,将显示结果同时输出到打印机。选择“to file 文件名” ,将显示结果同时输出到指定的文件中。若省略它们,则显示结果值输出到屏幕上。

  5. 删除内存变量

    cleat memory													# 删除所有用户自定义内存变量。
    release <内存变量表>												# 删除指定的用户自定义内存变量。
    release all [like 变量通配名|except 变量通配名] [extended]		# 删除某一类内存变量。
    	# 选择“except”,将删除与变量通配名不匹配的内存变量。extended选项主要用于在程序中删除全局变量。

数组简介

  1. 数组:实际工作中常常需要使用一组内存变量来存储某些想关的数据。

  2. 定义数组:定义一维或二维数组declare|dimension <数组一>(行[,列])[,数组二(行[,列])……]

  3. 给一个数组赋值:<数组名>(行,列) = <表达式>。

  4. 数组的删除:使用删除内存变量的命令会删除整个数组。

常用函数的功能

  1. Visual FoxPro 的函数实质上是一段程序。有函数名和()组成,你的到值叫做返回值,括号中加的是参数。

  2. 按照函数的功能可以把函数分为数值函数日期和时间函数字符函数测试函数转换函数等类型。

  3. 数值函数

    1. 绝对值函数`abs(数值表达式)`。
    2. 符号函数`sign(数值表达式)`、测试“表达式”的值。是正数则返回1;负数是-1;0就是返回0。
    3. 取整函数`int(数值表达式)`。
    4. 取最小整数函数`ceiling(数值表达式)`、返回大于或等于“表达式”的值的最小整数。
    5. 取最大整数函数`floor(数值表达式)`、返回小于或等于“表达式”的值的最大整数。 
    6. 四舍五入函数`round(数值表达式,有效位数)`、对“数值表达式”的值按指定的“有效位数”进行四舍五入。
    7. 求余数函数`mod(数值表达式1,数值表达式2)`。
    8. 平方根函数`sqrt(数值表达式)`。
    9. 圆周率函数`pi()`。
    10.自然对数函数`log(数值型函数)`。
  4. 日期和时间函数

    1. 日期函数`date()`、返回当前系统时间。默认格式为mm/dd/yy。
    2. 年函数`year(日期表达式)`。
    3. 月函数`month(日期表达式)`。
    4. 日函数`day(日期表达式)`。
    5. 时间函数`time()`、返回当前系统时间。返回时间的默认格式为 hh:mm:ss。
    6. 系统日期时间函数`datetime()`。
  5. 字符函数

    1. 生成空格函数`space(空格个数)`。
    2. 删除先导空格函数`ltrim(字符表达式)`。
    3. 删除尾随空格函数`rtrim(字符表达式)`。
    4. 删除先导和尾随空格函数`alltrim(字符表达式)`。
    5. 左子串函数`left(字符表达式,字符个数)`。
    6. 右子串函数`right(字符表达式,字符个数)`。
    7. 子子串函数`substr(字符表达式,起始位置[,字符个数])`。
    8. 求子串位置函数`at(字符表达式1,字符表达式2[,数值表达式])or atc(字符表达式1,字符表达式2[,数值表达式])`、若字符表达式1是字符表达式2的子串,则at函数返回字符表达式1在字符表达式2的位置。若不是子串,则函数返回0。可选项数值表达式用于指定首字符出现的次数,其默认值是1。
    9. 子串替换函数`stuff(字符表达式1,起始位置,长度,字符表达式2)`、用字符表达式2的值替换字符表达式1中有起始位置和长度指定的子串。如果长度的值为0,则字符表达式2插在起始位置指定的字符前面。如果字符表达式2是空字符串,则删除字符表达式1中由起始位置和长度指定的子串。
    10. 字符串匹配函数`like(字符表达式1,字符表达式2)`、比较两个字符串在对应位置上的字符,若所有对应的字符都匹配,则函数返回真值,反之假值。
  6. 测试函数

    1. 测试字符串长度函数`len(字符型表达式)`。
    2. 测试数据是否为空函数`emtype(表达式)`、是空返回真值,反之假值。
    3. 测试数据类型函数`type(表达式)`、type的返回值为:C表示字符型、D表示日期型、L表达式逻辑型、M表示备注型、N表示数值型、S表示屏幕型、U表示未定义的数据类型、Y表示货币型。
    4. 测试数据范围函数`between(表达式1,表达式2,表达式3)`、测试表达式1是否在表达式2和表达式3之间。在真值,不在假值。
    5. 测试数据类型函数`vartype(表达式[,逻辑表达式])`、若表达式是一个数组,则根据第一个数组元素的类型返回字符。若表达式的值是null,则当逻辑表达式的值为真时返回表达式的原数据类型,当逻辑表达式的值为假货省略逻辑表达式时返回X。
    6. 表文件头测试函数`bof([工作区号|别名])`、判断记录指针是否指向文件头若是,则返回真值,否则返回假值。
    7. 表文件尾测试函数`eof([工作区号|别名])`、判断记录指针是否指向文件尾若是,则返回真值,否则返回假值。
    8. 记录号测试函数`recno([工作区号|别名])`、返回指定表文件中当前记录的记录号。
    9. 记录个数测试函数`reccount([工作区号|别名])`、返回指定表文件中的记录个数,如果指定的工作区号没有表打开,则函数返回0。
    10. 记录删除测试函数`delete([工作区号|别名])`、测试指定表文件的当前记录是否有删除标记。有返回真值没有返回假值。
  7. 转换函数

    1. 数值转换为字符函数`str(数值表达式[,长度[,小数位数]])`。
    2. 字符转换为数值函数`val(字符表达式)`、val函数装换数据时,从左到右依次转换,遇到非数字字符就停止转换。默认:0.00。
    3. 字符转换为日期函数`ctod(字符表达式)`。
    4. 字符串转换为日期时间函数`ctot(字符表达式)`。
    5. 日期时间转换为字符串函数`ttoc(日期时间表达式[,1])`、若选择1,则按“yyyymmddhhmmss”的合适返回结果,若忽略则按“mm/dd/yy HH:MM:SS”的格式返回结果。
    6. 日期转换为字符函数`dtoc(日期型表达式[,1])`、选择“1”,将按yyyymmdd的格式返回结果。缺省该选项,将按mm/dd/yy返回结果。
    7. 小写装换为大写函数`upper(字符表达式)`。
    8. 大写转换为小写函数`lower(字符表达式)`。
    9. 字符转换为ascll码函数`asc(字符表达式)`。
    10. ascll转换为字符函数`chr(数值表达式)`。
  8. 其他函数

    1. 最大值函数`max(表达式1,表达式2,表达式3,……)。`
    2. 最小值函数`min(表达式1,表达式2,表达式3,……)`。
    3. 条件测试函数`iif(逻辑表达式,表达式1,表达式2)`、测试逻辑表达式的值为真,则返回表达式1反之返回表达式2的值。
    4. 宏替换函数`&<字符型变量>[.]`、替换指定字符型变量的值,即函数值是变量中存放的字符串。如果函数与其后的字符没有明确分界,则要使用“.”作为函数的结束标记。

使用项目管理器管理文件

  1. 项目维嘉个对应的炫目管理器可以帮助用户管理各种文件。

常用的文件类型

  1. Visual FoxPro 可以使用多种类型的文件,文件类型不同,其作用不同,扩展名也不同。

  2. Visual FoxPro 常用的文件类型

    文件类型 扩展名 文件类型 扩展名
    表文件 .DBF 表备注文件 .FPT
    报表文件 .FRX 报表备注文件 .FRT
    标签文件 .LBX 标签备注文件 .LBT
    表单文件 .SCX 表单备注文件 .SCT
    数据库文件 .DBC 复合索引文件 .CDX
    项目文件 .PJX 项目备注文件 .PJT
    文本文件 .TXT 屏幕格式文件 .FMT
    查询程序文件 .QPR 程序文件 .PRG
    应用程序文件 .APP 可执行文件 .EXE
    菜单格式文件 .MNX 菜单备注文件 .MNT
    菜单程序文件 .MPR 内存变量文件 .MEM

数据库和表

  1. Visual FoxPro 使用表文件保存数据,使用数据库文件管理表和表与表之间的关系。

  1. 在实际生活中,使用表格保存数据时需要先绘制表格,在填入数据。类似地,要使用Visual FoxPro 的表保存数据,也需要先定义表结构,在输入数据。

  2. 表结构由字段定义。每个字段有4个属性:字段名称、字段类型、字段宽度、小数位数

  3. Visual FoxPro 的字段类型有:字符型、货币型、数值型、浮点型、日期型、日期时间型、双精度型、整型、逻辑型、备注型、通用型、字符型(二进制)、备注型(二进制)

设计表的结构

  1. 要使用Visual FoxPro 的表保存数据,首先需要分类组织数据,被设计表结构;其次建立表结构,将数据输入表,并保存表文件。

  2. 组织数据:实际生活中使用表格管理大量数据,如果处理的数据混乱无序,将给工作带来许多不便为了有效地管理各种各样的数据,人们常常根据需要把数据进行分类、整理,按一定的原则组织数据。

  3. 字段和记录

    1. 字段和记录都是Visual FoxPro 的重要概念。表的数据项称为字段,表中相关字段值的值组成的集合称为记录。

    2. 一个表可以存放多达10亿条记录。一个表最多允许有255个字段。

    3. 数据库表每个字段的大小为128个字节,自由表是10个字节。

    4. 字段属性和字段类型。

    5. 字段类型 类型代码 说明 最大宽度
      字符型 C 存储字符型数据 254个字节
      货币型 Y 存储货币型数据 系统规定宽度为8个字节
      数值型 N 存储数值型数据 20位
      浮动型 F 存储数值型数据 20位
      日期型 D 存储日期型数据 系统规定宽度为8个字节
      日期时间型 T 存储日期时间型数据 系统规定宽度为8个字节
      双精度型 B 存储双精度型数据 系统规定宽度为8个字节
      整型 I 存储整型 系统规定宽度为4个字节
      逻辑型 L 存储逻辑型数据 系统规定宽度为1个字节
      备注型 M 存储不定长的文本 系统规定宽度为4个字节
      通用型 G 存储OLE对象 系统规定宽度为4个字节
    6. 表文件是Visual FoxPro 最重要的文件之一。表设计器是建立个修改表文件的重要工具。用户可以使用项目管理器、菜单或命令启动表设计器,建立和修改表文件。

  4. 使用命令创建表

    create<table>														# 创建表的命令,打开表设计器新建一个Visual FoxPro 表
    # 创建表的sql命令:SQL是Structured Query Language (结构化查询语言)的缩写,它是关系数据库语言的国际标准。SQL命令功能强大,又非常简洁。
    create table|dbf <表文件名>(<字段名> <类型>[(宽度[,小数位数])] [,primary key 表达式 tag 索引名] [,foreign key 表达式 tag 索引名 references 表文件名 [tag  索引名 ]])									# 创建表的SQL命令、选择primary key 就是建立主索引、foreign key 就是建立外键(建立关系)。
    copy to <table> [ fields 字段列表] [for 条件]							# 复制表的命令、选择fields 指定数据复制到新表中、use打开的是需要复制的。
    copy structure to <table> [fields 字段列表]							 # 复制表结构的命令、选择fields就是被选中的结构复制到新表中,确实该选项则全部复制。

数据库

  1. 实际工作中管理数据时,常常需要使用多个表。Visual FoxPro 使用数据库文件管理表和表与表之间的关系。

  2. 创建数据库

    create database <database>												# 创建数据库
    modify database [database|?] [nowait] [noedit]							# 打开数据库设计器
    	# nowait 选项只在程序中使用。选择该选项,则数据库设计器打开后程序才继续运行。
    	# 选择 noedit 可禁止修改数据库
    delete database <database|?> [deletetables] [recycle]					# 删除数据库的命令
    	# 选择 deletetables 可指定在删除数据库文件时从磁盘上删除该数据库包含的表文件;若省略,则删除数据库是不从磁盘上删除数据库包含的表文件。
    	# 选择 recycle 可指定将删除的数据库文件和表文件放入Windows的回收站中,如果需要,可以从回收站找中还原它们。
  3. 打开和关闭当前数据库

    open database <database>												# 使用数据库之前先打开数据库、可以打开多个数据库。
    set database [database]													# 设置当前数据库 
    set database 															# 取消当前数据库
    close database 															# 关闭数据库
    close all																# 关闭所有打开的文件的命令
  4. 添加与移去表

    # 数据库表和自由表,一个表可以是自由表也可以是数据库表。
    add table <table|?> [name longtable]									# 向数据库添加表
    remove table <table|?> [delete] [recycle]								# 从数据库移去表
    	# 选择 delete 则不仅将数据库表移除,而且还从磁盘上删除该表。
    	# 选择 recycle 将移除的表翻到Windows 的回收站中。

显示和修改

  1. 表的结构应该相对稳定,才有利于管理数据。但随着实际请款的变化,表的结构也可能需要修改。

  2. 打开和关闭表

    1. 工作区:生活中常常需要使用多个表。为了便于管理,Visual FoxPro 提供了**32767个工作区**。启动Visual FoxPro 时1号工作区是当前工作区。
    2. 选择当前工作区的命令`select<工作区>|<别名>`。
    3. 使用命令打开表
       - use <表文件名>[in 工作区号] [alias 别名] [noupdate] [again]
       - noupdate,则指定表文件只读,即不用需修改表的数据
       - again 可以再次打开己在其他工作区中打开的表。
    4. 使用命令关闭表
       - use [ in 工作区 | 别名]
  3. 显示和修改表结构

    1. 使用命令显示表的结构
       - display | list  structure [in 工作区号| in 别名] [ to printer | to file 文件名]
       - to printer 可将显示结果输出到打印机。to file 可将显示结果输出到指定的文本文件。
    2. 使用命令修改表的结构
       - modify structure
  4. 浏览和编辑

    1. 使用命令浏览编辑数据
    
       - browse [fields 字段列表]  [for 条件] [freeze 字段名] [lock 锁定字段数] [noappend] [nodelete] [noedit]
       - 选择 fields 只显示字段列表中的,不选择全部显示,顺序由字段列表决定。
       - 选择freeze 把字段光标冻结在指定字段上,该字段是唯一可以修改的字段。
       - 选择 lock 可以将浏览窗口分成两个窗格,左边窗格显示指定数目的字段。
       - 选择 noAPPend  指定不能向表添加新记录。选择nodelete 指定不能删除。
       - 选择noedit 指定不能修改记录的数据。
    
    2. 使用命令编辑数据
    
       - edit | change [fields 字段列表] [范围] [for 条件]
    
       - “范围”的值
    
         | “范围”的值 |                   意义                   |
         | :--------: | :--------------------------------------: |
         |    all     |                 所有记录                 |
         |  record n  |                第n条记录                 |
         |   next n   |       从当前记录开始连续的n条记录        |
         |    rest    | 从当前记录开始直到最后一条记录的所有记录 |
    
         
  5. 定位记录和显示数据

    使用命令移动记录指针
    
    1. 绝对指针移动命令
       - go | go top | go | bottom |<记录号>
       - 选择top是定位到第一条
       - bottom 可把当前表的记录指针移到最后一条记录上。
    2. 相对指针移动命令
       - skip [记录数]
       - 如果不加记录数则记录指针向文件尾移动一条记录。
    3. 测试记录的函数
       1. 测试当前记录号的函数
          - recno()
       2. 测试记录总数的函数
          - reccount()
    4. 显示数据
       - display | list [all] [fields 字段列表] [范围] [for 条件] [off] [to printer| to file 文件名]
       - 选择 off是不显示记录号
       - to printer 可将显示结果输出到打印机。to file 可将显示结果输出到指定的文本文件。

追加、删除和更新

  1. 现实生活中管理数据时,追加记录是不可缺少的操作。

  2. 追加记录

    1. 追加记录命令
       - append[blank]
       - 选择blank 追加一条空记录
    2. 追加记录的SQL命令
       - insert into <表名> [(<字段名列表>)] values (<表达式列表>)
    3. 使用命令从表文件追加记录
       - append from <表文件名> [ fields 字段列表] [for 条件]
       - 把指定表的文件中的记录追加到当前表。
    4. 使用命令从文本文件追加记录
       - append from <文本文件名> type <文件类型> [ fields 字段列表] [ for 条件]
       - “文本文件名” 用于指定提供数据的文本文件。
       - “数据类型” 用于指定文本文件的数据格式。通常使用sdf 和 delimited 两种类型。其中sdf表示标准格式(也称为无格式),这种格式的特点是数据的前后空格保留,数据之间无分隔符,字符串也不乱起来,各行数据的长;delimited表示紧凑格式(也称为带格式),这种格式的特点是数据的前后空格不保留,用空格分隔各个数据项,字符串用定界符括起来,各行数据不等长。
    5. 表文件转换为文本文件
       - copy to <文件名> type <文件数据类型> [fields 字段列表] [for 条件]
       - 将当前表的数据复制到一个文本文件中。
       - 文件名用于指定文本文件的文件名,该文件的默认扩展名是.txt
       - 选择 with 定界符 ,可使用空格分隔个字段,并把字符串用指定的定界符括起来;选择with blank ,可使用空格分隔个字段,字符串不用引号括起来。若缺省这两项,则使用逗号分隔字段,字符串用双引号括起来。这种格式的文件也称为带格式文件。
       - 
  3. 删除记录

    1. 使用命令逻辑删除记录
       - delete [all] [for 条件]
       - 缺省这两项只逻辑删除当前记录。
    2. 逻辑删除记录的SQL命令
       - delete from <表文件名> [where 条件]
    3. 测试记录是否有删除标记的函数
       - delete()
    4. 使用命令取消记录的物理标记
       - recall [all] [for 条件]
    5. 使用命令物理删除记录
       - pack
    6. 使用命令物理删除所有记录
       - zap
    7. 使用命令恢复被逻辑删除的命令
       - recall [范围] [ for 条件]
  4. 更新数据

    1. 成批替换数据
       - replace <字段名1> with <表达式1> [,<字段名2> with <表达式2>......] [all] [for 条件]
    2. 更新数据的SQL命令
       - update <表文件名> set <字段名1> = <表达式1> [, <字段名2> = <表达式2> …] [ where 条件]
       - 

有序显示数据

  1. 向表追加记录时,Visual FoxPro 按照记录的先后顺序存储数据。但是在实际应用中,即常常需要对记录重新排序,按照不同的顺序使用表的记录。索引可以对记录逻辑排序,它只改变记录的逻辑顺序,并不改变记录的物理顺序,也不会建立表。一个表可以建立多个索引,每个索引提供一种逻辑顺序,用户可以按照多种不同的顺序使用表的记录。

  2. 索引根据表中某一特定的字段或表达式对记录进行排序。用作排序依据的字段或表达式称为索引关键字。跟剧对索引的关键字的不同要求,可以将索引分为一下4种类型。

  3. 索引类型 是否允许出现重复关键字 建立什么类型的表 一个表中建立个数
    主索引 数据库表 一个
    候选索引 数据库和自由表 多个
    普通索引 数据库和自由表 多个
    唯一索引 数据库和自由表 多个

创建索引和对记录排序

  1. 索引文件

    1. Visual FoxPro 的索引文件可以分为两类:一类是传统的单索引文件,默认扩展名是IDX。一个单索引文件只存放一个索引。另一类是复合索引文件,默认扩展名是CDX。一个复合索引文件可以存放多个索引,其中各个索引用索引名来区分。如果复合索引文件的主文件名与对应表的主文件名相同,则称它为结构索引文件。结构索引文件有一些很好的性质。在表这机器中创建的索引都存放在结构索引文件中。

  2. 使用命令创建索引

    1. index on <单索引文件名> | tag <索引名> [ of 复合索引文件名] [ for 条件] [ descending] [unique| candidate]

    2. desc是降序,asc是升序

    3. 选择 of ,索引存放在指定的复合索引文件中。缺省该选项,索引存放在结构索引文件中,省去 descending,索引顺序为升序。

    4. 选择 unique ,可建立唯一索引。选择 candidate ,可建立候选索引。若省略这两个选项,则建立普通索引。

  3. 当前索引

    1. 当用户需要按照多个不同的顺序使用表中的记录时,通常利用索引对记录进行逻辑排序。一个表可以建立多个索引,但任一时刻控制记录逻辑顺序的索引只有一个,这个索引称为当前索引。指定当前索引后,记录的顺序就由该索引决定。用户可以使用命令和工作区属性对话框至当前索引。

  4. 打开索引文件

    1. set index to [ 索引文件列表]

  5. 使用命令指定当前索引

    1. set order to < 索引名> [of 索引文件名] [ascending|descending]

    2. 选择of 索引文件名,指定该索引文件中的索引为当前索引。缺省该选项,则指定结构索引文件中的索引为当前索引。

  6. 维护索引

    1. 编辑索引关键字,可以更改记录排序的结果,所以应及时维护索引,是索引文件中的索引正确反映记录的最新状态。维护索引通常使用方法。

    2. 自动维护索引

      • Visual FoxPro 可以自动维护打开的索引文件中的索引。

    3. 使用命令维护索引

      • 当表文件和需要维护的索引文件都打开后,可以执行重新索引命令来维护索引。

      • reindex

      • 对当前表的所有打开的索引文件重新索引。

    4. 打开表和索引文件

      • use <表文件名> [in 工作区号] [index 索引文件表] [order[tag]索引标记 [of 复合索引文件] [ascending|descending]]

      • 选择order [tag] 索引标记 [of 复合索引文件]可指定,复合索引中的某个索引为当前索引。若省略of 复合索引文件,则指定结构索引文件中的某个索引为当前索引。

    5. 使用命令删除索引

      • delete tag <索引名|all> [of 复合索引文件名]

检索、统计和使用多个表的数据

  1. 保存数据的目的是为了更好地使用数据。要从大量数据中找出需要的数据,值使用浏览数据和显示数据的方法是远远不够的,还需要掌握检索数据的方法。

  2. 检索数据

    1. 使用命令检索数据
       - locate for<条件>
       - 在当前表中查找班组条件的第一条
    2. 继续检索命令
       - continue
       - 在当前表中继续查找满足条件的下一条记录。
    3. 使用索引快速检索数据
       - seek <表达式> [tag 索引名] [in 工作区号| 别名]
       - 在当前表的索引中检索指定表达式的值
    4. 测试检索是否成功的函数
       - found()
       - 测试记录指针是否在文件尾的函数
         - eof()
    5. 使用命令对记录进行物理排序
       - sort to <新文件名> on <字段1> [/a] [/d] [/c] [,<字段2> [/a] [/d] [/c] ……] [asc|desc] [fields 字段列表] [范围] [ for 条件]
       - “新文件名” 用于指定排序生成的表文件的文件名,该文件名不能与当前表同名。
       - “字段1”,“字段2”,……用于指定作为排序关键字的字段。如果使用多个字段排序,则系统将先按第一个字段,对于第一个字段值相等的记录,再按第二个字段排序,以此类推。
       - 选择“/a”,可指定按升序排,选择"/d",可指定按降序排"/c",可指定排序时不区分字母的大小写。它们都会对其前面的字段起作用。系统默认的是升序,且区分大小写。
  3. 统计数据

    1. 求和命令
       - sum [ 表达式列表] [ for 条件]
    2. 求平均值命令
       - average [ 表达式列表 ] [ for 条件 ]
    
    2.6.3 创建表间关系
    
    1. 表间关系
       - Visual FoxPro 可以在当前表和其他打开的表之间建立一对一的关系或一对多的关系。两个表建立关系后,当前表称为主表,与之建立关系的表称为子表。建立了表之间的关系后,当主表的记录指针移动时,系统自动移动子表的记录指针指向匹配的记录。
    2. 使用命令创建表之间的一对一关系
       - set relation to [关键字 into 别名……]
       - 选择 关键字 into 别名 ,指定建立关系。缺省该选项,则取消关系。其中关键字指定建立关系的关键字,别名是子表的别名。
    3. 使用命令创建表之间的一对多关系
       - set skip to <别名>
       - 注意:
         - Visual FoxPro 使用建立一对一关系的关键字建立一对多的关系。因此,建立一对多的关系之前必须先建立一对一的关系。
  4. 创建参照完整性

    1. Visual FoxPro 的参照完整性规则由更新规则、删除规则、插入规则组成。更新规则可以使编辑主表关键字的结果自动反映到子表,删除规则可以使删除主表记录是自动删除子表的相关记录,插入规则可以检查在子表插入记录的合法性。它们用于保护数据库表之间数据的正确性。

    2. 规则类别 规则名 意义
        级联 若修改主表关键字的值,则用新的关键字值更新子表的所有相关记录
      更新规则 限制 若子表中有相关记录,则禁止更新主表对应的关键字值
        忽略 不论子表是否存在相关记录,均可以修改主表关键字的值
        级联 若删除主表的记录,则删除子表的所有相关记录
      删除规则 限制 若子表中有相关记录,则禁止删除主表对应的记录
        忽略 不论子表是否存在相关记录,均可以删除主表的记录
      插入规则 限制 若主表不存在匹配的关键字值,则禁止在子表中插入记录
        忽略 不论主表是否存在匹配的关键字值,均可以在子表中插入记录
    3. 数据完整性

      • 数据完整性包括域完整性、实体完整性和参照完整性

        1. 域完整性

          • 域完整性是指定数据的取值范围。在Visual FoxPro 中,通过定义字段的数据类型和宽度,以及设置字段的有效性规则来实现域完整性。

        2. 实体完整性

          • 实体完整性是保证表中记录唯一的特性,即在一个表中不允许有重复的记录。Visual FoxPro 使用主索引和候选索引实现数据的实体完整性。

查询与视图

  1. 在管理数据的工作中,查询数据和修改数据是最常用的操作之一。利用Visual FoxPro 的查询功能可以方便地检索出需要的数据,借助Visual FoxPro 的视图可以方便地更新数据。

查询

  1. 查询是从指定的表或视图中提取满足条件的记录,并按照指定的输出去向输出查询结果。查询文件的默认扩展名为.QPR,但该文件实质上是一个文本文件,里面存放着实现查询功能的SQL命令。

    do <查询文件名>														# 使用命令运行查询
    modify query <查询文件名>											# 使用命令打开查询文件
  2. 查询去向:Visual FoxPro 可以用多种形式输出查询结果。如果设计查询时不指定查询去向,则系统默认在浏览窗口中显示查询结果。

    查询去向 含义
    浏览 将查询结果输出到浏览窗口
    临时表 将查询结果保存到一个临时表中
    将查询结果保存到一个指定的表中
    图形 将查询结果输出到 Microsoft Graph 图形文件中
    屏幕 将查询结果输出到当前活动窗口中
    报表 将查询结果输出到一个报表文件中
    标签 将查询结果输出到一个标签文件中

    注意:临时表保存在内存中。当关闭临时表时,系统自动删除该临时表。

使用SQL命令查询数据

  1. Visual FoxPro 的查询功能实质上是调用查询数据的SQL语句。

查询数据的SQL命令

  • 查询命令

    • select [distinct] [输出数量] <查询项列表>|* from <数据源> [where 条件] [group by 分组项列表] [having 条件] [order by 排序项列表] [输出对象]

    • *号代表所有查询项列表。

    • 选择 distinct ,不输出重复的记录。

    • 选择输出数量,值输出指定数量的记录。

    • 选择 having 条件 ,可以指定分组满足的条件。

    • 输出对象,将查询结果输出到指定对象。缺省,则查询结果默认输出到浏览窗口。

    • order by 是排序 的desc是降序,asc是升序。

  1. 简单的计算查询

    • count :计数

    • sum:求和

    • avg :求平均值

    • max:求最大值

    • min:求最小值

  2. 指定查询去向

    • [into 目标| to file 文件名 [additive]|to printer|to screen]

    • 选择 to file 文件名 指定查询结果输出到文本文件中。选择[additive],查询结果追加到文件尾,否则将覆盖原来的内容。

    • 选择 to printer 指定查询结果送打印机输出。

    • 选择 to screen 指定查询结果显示到屏幕上。

    • 选择 into 目标,指定查询结果输出到表文件或数组中。

    • 选项 意义
      DBF 表文件名 将查询结果保存到一个表文件中
      CURSOR 表文件名 将查询结果保存到一个只读的临时表中
      ARRAY数组名 将查询结果保存到一个二维数组中
      select * from a into dbf ad
      select * from a to screen
  3. 多表查询

    • 在数据源中指定较复杂的联接条件。是用select 命令查询多个表的数据时,数据源中不仅要指定查询的表名,通常还要指定表之间的联接类型和联接条件。

    • [数据库名 !] <表名> [inner|left|right|full] join[数据库 !] <表名> [on 联接条件]

    • 选项 名称 说明
      inner 内部联接 只返回完全满足联接条件的记录
      left 左联接 返回join左侧表中的所有记录以及右侧表中匹配的记录
      right 右联接 返回join右侧表中的所有记录以及左侧表中匹配的记录
      full 完全联接 返回两个表中的匹配和不匹配的所有记录
      select * from a left b on a.id = b.id where id <=10
      select * from a inner b on a.id = b.id where id <=10

创建报表和视图

  1. Visual FoxPro 有两种视图,本地视图用于更新本地计算机存储的数据,远程视图用于更新远程服务器上存储的数据。

  2. 创建和运行本地视图

    create view <viewName> as <查询语句>								 # 使用SQL命令建立视图,为当前数据库建立视图
    drop view <viewName>												# 删除视图的SQL命令,删除当前数据库中指定的视图
  3. 远程视图:Visual FoxPro 的远程数据可以更新远程 ODBC (Open DataBase Connectivity)数据源中的数据。

  4. 报表的数据源可以是表或视图。报表文件的默认扩展名为FRX。

  5. Visual FoxPro提供了多种创建报表的方法,用户可以使用报表向导、报表设计器或命令建立报表。

    create report <reportFileName>									# 使用命令新建报表
    modify report <reportFileName>									# 使用命令打开报表文件

其他SQL命令

  1. 修改表结构的命令的第一种

    1. alter table <表名> add | alter <字段名> <类型> [(宽度[,小数位数])] [check <表达式> [error 错误提示信息]] [default 默认值] [primary key |unique]

    2. 选择add ,指定添加字段。选择alter ,指定修改字段。

    3. 选择 check,可以指定字段的有效性规则,选择 error 错误提示信息,可以指定不满足有效性规则时的现实信息。

    4. 选择default 默认值,可以指定字段的默认值。

    5. 选择 primary key ,指定创建主索引。

    6. 选择 unique ,指定创建候选索引。

  2. 修改表结构的命令的第二种

    1. alter table <表名> alter <字段名> [set default 默认值] [set check 表达式 [error 错误提示信息]] [drop default] [drop check]

    2. 字段名,指定需要设置设置值或有效性规则的字段名。

    3. 选择,set check 表达式,可以指定字段的有效性规则;选择error错误提示信息,可以指定不满足字段的有效性规则时的提示信息。

    4. 选择 set default 默认值 ,可以指定字段的默认值。

    5. 选择 drop default ,可以删除字段的默认值。

    6. 选择drop check ,可以删除字段的有有效性规则。

  3. 修改表结构的命令的第三种

    1. alter table <表名> [ drop <字段名1>] [set check 表达式1 [error 错误提示信息]] [drop check] [add primary key 表达式2 tag 索引名] [drop primary key ] [add unique key 表达式3 tag 索引名] [drop unique key ] [rename column 字段名2 to 字段名3]

    2. 选择 drop <字段名1>,可以删除指定的字段。

    3. 选择 set check 表达式1,可以指定字段的有效性规则,选择 error 错误提示信息,可以指定不满足有效性规则时显示信息。

    4. 选择drop check ,可以删除字段的有效性规则

    5. 选择 add primary key表达式 2 tag 索引名,可以指定创建主索引。

    6. 选择drop primary key ,可以删除主索引。

    7. 选择 add unique key 表达式3 tag 索引名,可以指定创建候选索引。

    8. 选择drop unique key ,可以删除候选索引。

    9. 选择 rename column 字段名 2 to 字段名3 ,指定将 字段名2 改名为 字段名3。

结构化程序设计基础

  1. 人们常常利用Visual FoxPro 提供的程序设计功能,编写程序快速、方便地完成复杂的数据管理工作。Visual FoxPro支持结构化程序设计和面向对象程序设计。

  2. 创建与运行程序:Visual FoxPro 的程序文件是一个文本文件,程序文件的默认扩展名是.PRG。

    modify command <程序文件名>											# 建立程序文件的命令
    do <程序文件名>														# 运行程序的命令
  3. 添加注释:可以使用"*"号或note命令给某一行加注释,也可以使用"&&"顾浩在语句行后面添加注释。

编写程序

  1. Visual FoxPro 提供了3种基本的程序结构:顺序结构、选择结构、循环结构

  2. 常用程序命令

    clear														# 清屏命令
    
    # 简单输入\输出命令
    accept [提示信息] to <内存变量> 								# 输入字符串命令
    input [提示信息] to <内存变量>									# 输入表达式命令
    wait [提示信息] [to 内存变量] [window [at 行,列]] [nowait] [Timeout 时间] [cleat|noclear ]			# 输入一个字符命令
    	# 选择window at 行,列,在系统窗口显示信息,其中的at行,列可以指定窗口的位置。
    	# 选择Timeout 时间,指定等待的时间;缺省该选项,则无限等待,知道用户按键为止。
    	# 选择 nowait ,将不等待用户按键
    	# 选择noclear ,则不关闭提示窗口。知道执行下一条wait window 命令或wait clear 命令为止。
    	
    # 格式化输入/输出命令
    @<行,列> say <显示信息>								   	 # 格式化输出命令。
    @<行,列> [say 显示信息] get <变量>							# 格式化输入命令。
    row()													 # 测试行坐标的函数其函数格式为
    col()													 # 测试列坐标的函数其函数格式为
    
    # 设置程序运行环境:Visual FoxPro 提供了一个集成化的应用环境,但这个环境可能不适合用户开发的应用程序运行。所以,应用程序开头通常使用环境设置命令设置新的环境,应用程序结束之前又使用环境设置命令恢复Visual FoxPro的应用环境。
    set talk on |off											# 设置会话状态,设置是否显示某些命令执行的结果
    set safety on | off											# 设置文件保护命令,设置删除文件数据时是否显示提示信息。
    clear all													# 清除内存变量命令,清除用户自定义内存变量和对象
    cancal														# 终止程序运行命令,中止程序运行,清除局部变量,返回命令窗口。

选择结构程序

  1. 选择结构分为3种:单分支选择结构、双分支选择结构、多分支选择结构

    # 单分支
    if <条件>
    	<语句组>
    endif
    
    # 双分支:双分支选择结构。无论是否满足指定条件,都能执行其中一个程序分支,并且只能执行一个程序分支。
    if <条件>
    	<语句组>
    else 
    	<语句组>
    endif
    
    # 多分支:多分支选择结构通常有一个程序分支,但最多执行其中一个程序分支,也可能所有程序分支都不执行。
    # 如果所有case 后面的条件都不满足,当有otherwise选项时,执行对应的“语句组”,没有otherwise选项时,直接执行case后面的语句。
    do case 
    	case <条件1>
    		<语句组1>
    	case <条件2>
    		<语句组2>
    	case <条件n>
    		<语句组n>
    	[otherwise
        	语句组]
    endcase

循环结构程序

  1. 循环结构分为3种:基于条件的循环、基于记录的循环、基于次数的循环

    # 基于条件的循环
    do while <条件>
    	<语句组>
    end do
    
    # 基于记录的循环
    scan [for 条件]
    	<语句组>
    endscan
    
    # 基于次数的循环,不加步长默认为1
    for <变量>=<初值> to <终值> [step 步长]
    	<语句组>
    endfor
    
    # 循环控制命令
    loop																# 终止本次循环命令
    exit																# 结束循环命令

调试过程

  1. 程序中的错误通常分为两类:语法错误和逻辑错误。程序中命令格式、命令的关键字或程序结构出现错误将导致语法错误,命令或表达式使用不当导致逻辑错误。

  2. 过程是为了实现某个功能而编写的一段程序,它与子程序有许多相似之处。用户可以使用创建子程序的方法创建过程,可以像调用子程序一样调用过程。

  3. 过程定义过程

    procedure <过程名>
    	<语句组>
    endproc
    
    set procedure to [过程文件名] [additive]								# 打开过程文件,选择 additive ,则打开过程文件时不关闭原先已经打开的过程文件。
    release procedure <过程文件表>										# 关闭过程文件
    do <程序|过程名> [with 参数表]										  # 传递参数
    	# 接收参数的命令
    	# parameters <参数表>
    	# lparameters <参数表>
    	# 这里的参数表是变量,p命令声明的变量是私有变量,l命令声明的变量是局部变量。
  4. 过程文件:过程文件的默认扩展名是.PRG,一个过程we年可以存放多个过程。用户可以使用创建程序文件的方法创建过程文件。

内存变量的作用域

  • 内存变量的作用域也就是内存变量的作用范围,他指明了内存变量在什么范围内是有效的或能够被访问的。按照内存变量的作用域,可以将内存变量分为3类:全局变量、私有变量、局部变量

  1. 全局变量:在所有程序中都能使用的便来能够成为全局变量。全局变量必须先定义后使用。public<内存变量表>、它们的初值是逻辑假值。

  2. 私有变量:在程序中使用赋值命令或由系统自动建立的变量都是私有变量。私有变量只在程序和建立的子程序中有效,程序关闭后变量会自动删除。

  3. 局部变量:局部变量只在建立它的程序中有效,在其上级下级程序中无效。局部变量必须先定义后赋值。local<内存变量表>、初值为逻辑假值。

  4. 隐藏内存变量

    1. 从变量的作用与可知,如果子程序中的变量与主程序中的变量同名,当从子程序返回主程序时,系统默认把与主程序同名的变量的值转回主程序中,这使子程序可能无意识地改变主程序中变量的值,造成主程序运行混乱。用户可能在子程序中使用private命令隐藏上级程序可能存在的内存变量,

    2. private <内存变量表> | all [like 变量通配名|except 变量通配名]

    3. 选择like ,将隐藏所有与内存通配名匹配的内存变量。选择except ,将隐藏所有与变量通配名不匹配的内存变量。

  5. 对数组操作的函数

    1. 删除数组元素的函数adel(数组名,数字[,2]),返回1时是删除成功,-1时没有删除成功。

    2. 插入数组元素的函数ains (数组,数字[,2])

    3. 求数组长度的函数alen(数组[,数字]),数字的值为1或者2。对于一维数组,若果数字的值是1或者省略选项,则函数返回数组元素的个数;如果数字的值是2,则函数返回值是0。对于二维数组,如果是1则返回行数,如果是2则返回列数,如果省略数字则函数返回数组元素的个数。

  6. 表与数组交换函数

    1. 表的记录赋值到数组

      1. scatter [fields 字段表] [memo] to <数组名> [blank]

      2. 选择fields字段表,只复制指定字符安的内容;若省略则复制除备注型和通用型字段外的所有字段。

      3. 选择memo ,可制定复制备注型字段的内容。

      4. 选择blank,可建立一个空数组。个数组元素的类型和大小与对应字段相同。

    2. 数组的数据复制到表:gather from <数组名> [fields 字段表] [memo]

面向对象程序设计基础

  • 面向对象程序设计是当前流行的程序设计方法,也是程序设计的发展趋势。

用法

标签控件的属性

属性 用法 属性 用法
Name 对象的名称 Caption 对象的标题
Color 对象的颜色 FontName 标题的字体
FontBold 标题字体是否为粗体 FontSize 标题字体的大小
FontItalic 标题字体是否为斜体 ForeColor 标题字体的颜色
Width 对象的宽度 Height 对象的高度
Left 对象左边距离 Top 对象顶部距离
BackColor 对象的背景颜色 Visible 对象运行时是否可见
Enable 对象是否可用 ControlSource 指定与对象绑定的数据源

事件

类别 事件名 说明
鼠标事件 Click 在对象上单击鼠标左键时触发的事件
鼠标事件 DblClick 在对象上双击鼠标左键时触发的事件
鼠标事件 MouseMove 鼠标指针移动到对象上时触发的事件
鼠标事件 PightClick 在对象上单击鼠标右键时触发的事件
键盘事件 KeyPress 按下键盘的按键时触发的事件
控制焦点事件 GotFocus 对象获得焦点时触发的事件
控制焦点事件 LostFocus 与Gotfocus相反,对象失去焦点时触发的事件
改变控件内容事件 InteractiveChange 用户手动修改对象的值时触发的事件
改变控件内容事件 ProgrammaticChange 程序自动修改对象的值时触发的事件
表单事件 Load 创建(运行)表单时触发的事件
表单事件 Unload 关闭表单时触发的事件
表单事件 Resize 改变表单大小时触发的事件
表单事件 Activate 激活表单时触发的事件
表单事件 Deactivate 表单转变为非激活状态时触发的事件
表单事件 Init 创建对象时触发的事件
表单事件 Destroy 表单从内存中释放时触发的事件
数据环境事件 BeforeOpenTables 表打开前触发的事件
数据环境事件 AfterCloseTables 表关闭后触发的事件
计时器 imes 计时器计时到时触发的事件
出错 Error 程序在执行过程中出错时触发的事件

对象的引用

  1. 相对引用:从正在编写事件代码的对象(关键字this表示该对象)出发,向高一级(.parent)或低一级(.[对象名])逐层引用。

  2. 绝对引用:从最高层对象开始向低一级逐层引用。

  3. 关键字:thisform (当前对象所在的表单)和 thisformset(当前对象所在的表单集)。

    • 当在Command2上点击鼠标左键时:

      • thisform.pageframe1.page1.Command2.Caption = “确定”

控件

控件 描述
Label 用于显示文本信息的标签
Text 用于单行文本的输入框
Editbox 用于多行文本的编辑框
Command 命令按钮
Commandgroup 命令按钮组
Optiongroup 单选按钮组
Checkbox 复选框
Combobox 组合框,可以输入、可以下拉选项
Listbox 列表选择框
Spinner 微调按钮
Grid 二维表格
Imaage 用于显示图片的图像控件
Timer 能在一定时间循环执行行代码的定时器
PageFrame 包含若干页的页框
Line 水平线、垂直线或斜线
Shape 方框、圆或椭圆

 

面向对象程序设计的基本概念

  1. 对象

    • 现实生活中的对象就是一个具体的事物。

    • 在面向对象的程序设计中,对象是一个具有属性和方法的实体,是面向对象程序设计的基本元素

  2. 对象的属性和属性值

    • 现实生活中的每个对象有许多特性,每个特性有一个具体的值。

    • 在面向对象程序设计中,对象的特性称为对象的属性,描述对象特性的具体数据成为属性值。

  3. 事件和方法

    • 事件就是对象可以识别和相应的操作。它是预先定义的特定的操作。

    • 方法就是事件发生时对向执行的操作。

    • 调用格式

    • <表单>.<对象名>.<方法名>

    • thisform.release 关闭当前表单
      thisform.hide 隐藏当前表单
      thisform.show 显示当前表单
      thisform.refresh 刷新当前表单
      thisform.text1.setfocus 自动将焦点移动到text1文本框
  4. 类和子类

    • 某一种类型的对象具有一些共同的属性,将这些共同属性抽象出来就组成一个类。

    • 子类并不只是单纯地继承父类的属性,子类还具有各自特殊的属性。

  5. 类的继承性

    • 子类继承父类的属性说明类具有继承性。类的继承性使用户可以充分利用现有类派生出子类。

    • 类的继承性使得对父类所做的修改自动反馈到它的所有子类上。

  6. 类和对象的封装性

    • 现实生活中使用某些对象时,用户主要关心使用该对象的方法,而更少关心对象的内部属性。

    • 在Visual FoxPro 中,类也将对象的共同属性和方法封装在其内部,使得类派生出的对象也具有这些属性和方法。

面向对象程序设计方法简介

  1. 程序的事件驱动机制

    • 结构化的程序按照预定的流程执行。面向对象的程序则按照事件发生的顺序执行程序代码,这就是面向对象程序的事件驱动机制。

  2. 面向对象程序设计的基本方法

    • 由于面向对象程序事件驱动机制的优越性,使用面向对象的程序设计方法编写程序时,重点应考虑程序运行中可能产生的每一个事件和对应的方法以及用户界面的美观性。

      1. 设计应用程序界面

      2. 设置对象的属性值

      3. 编写事件过程

      4. 保存程序

      5. 运行调试程序

    • 案例6.1 设计应用程序正是按照这种方法,首先新建表单,并向表单设计器添加控件,设计用户界面,其次使用属性窗口设置对象的属性值,之后在代码窗口编写命令按钮的Cilck事件过程,最后保存程序和运行程序。

    • 使用Visual FoxPro 开发应用程序的基本方法并不是一成不变的。

表单

创建表单

  • Visual FoxPro 提供了多种创建表单的方法

  1. 使用命令创建表单

    • create form <表单文件名>

  2. 运行表单

    • do form <表单文件名>

  3. 打开表单

    • modify form <表单文件夹名>

表单的常用属性、方法和事件
  1. 表单常用属性
    • 属性 说明 默认值
      AlwaysOnTop 指定表单是否总是显示在其他打开的表单之上
      AutoCenter 指定表单初始化时是否让表单自动地在系统主窗口中居中
      BackColor 指定表单的背景颜色 21,12,12
      BorderStyle 指定表单的边框样式:0-关边框、1-单线边框、2-固定对话框、3-可调边框 form1,2
      Caption 指定表单标题栏显示的文本
      Closable 指定是否能通过单击右上角的“关闭框”来关闭表单
      Height 指定表单的高度
      MaxButton 指定表单右上角是否显示最大化按钮
      Minbutton 指定表单右上角是否显示最小化按钮
      Mowable 指定表单是否能够移动
      Picture 指定表单的背景图片  
      Scollbars 指定表单所具有的滚动条类型。可取值为:0-关,1-水平,2-垂直,3-即水平又垂直 0-关
      Titlebar 指定表单顶部是否显示标题栏(title) 1-开
      Width 指定表单的宽度  
      Windowstate 指定表单刚打开时是最小化、最大化还是正常显示状态 0-普通
      Visible 指定表单是显示还是隐藏
      WindowsType 指定是“关模式表单”还是“模式表单” 0-关模式
      Icon 指定表单的图标,显示在表单的左上角
      Name 指定表单的名称(在代码中引用时用的,与文件名没有关系) form1,2.。。
      1. Name、Caption和文件名和区别

        • Name:表单对象名,只在变成时使用

        • Caption:表单标题名,运行时显示在标题位置处:

        • 文件名:表单对应的文件名

      2. Visible与Enabled的区别

        • Visible:指定表单是否可见

        • Enabled:指定表单是否可用,或者是否可以响应用户的请求。

      3. “模式”与“非模式”的区别

        • 模式:只有本表单退出时,才可以激活别的表单。

        • 非模式:不关闭本表单,就可激活别的表单。

  2. 表单常用事件

    • Load事件:装载表单(创建表单之前)时,将会激发这个事件,而且表单被加载进内存;

    • Init事件:表单初始化(创建表单)时,将会激发这个事件;

    • Activate事件:表单激活时,将会激发这个事件;

    • GotFocus事件:表单接收焦点,由用户动作,或者在代码中使用SetFocus方法引起。

    • LostFocus事件:表单失去焦点时,将激活这个事件

    • Destroy事件:表单从内存中释放时,将会激发这个事件;

    • Unload事件:关闭表单时,将会激发这个事件,而且表单从内存中释放,在Destroy事件激发且所有包含的对象被释放后,才会激发Unload事件;

    • Deactivate事件:当表单不再处于激活状态时,将会激发这个事件;

    • Resize:改变表单大小时,将会激发这个事件;

    • Click:单击鼠标左键时,将会激发这个事件;

    • DblClick:双击鼠标左键时,将会激发这个事件;

    • RightClick:单击鼠标右键时,将会激发这个事件;

    • MouseDown、MouseUp、MouseMove三个常用的鼠标事件:在表单上按下鼠标、释放鼠标、移动鼠标时触发。

  3. 表单常用方法

    • Release方法:关闭、释放表单;

    • Refresh方法:重新绘制表单,并刷新表单中所有控件的属性。

    • Show方法:显示被隐藏的表单,相当于将表单的Visible属性这为.T.。

    • Hide方法:隐藏表单,相当于将表单的Visible属性这为.F.。

标签控件和文本框(TextBox)控件

  1. 标签控件的功能

    • 标签主要用于显示固定的文本信息。

  2. 标签控件常用属性

    • caption:指定标签的现实文本。可以在设计时设置,也可以在程序运行时设置或修改。

    • autosize:zutosize如果为真,标签在表单中的大小由caption属性中的文本长度决定,否则其大小由WIDTH和HEIGHT属性决定。

    • forecolor:设置标题的字体颜色。

    • backstyle:设置标签的背景是否透明,0透明,1不透明,默认为不透明。

    • name:标签对象的名称,是程序中访问标签的对象的标识。

  3. 文本框控件的功能:

    1. 用于显示和接收单行文本信息(不设置ControlSource属性),默认输入类型为字符型,最大长度为256个字符。

    2. 用于显示和编辑对应变量或字段的值(设置ControlSource属性为已有变量或字段名)。

  4. 文本框控件常用属性

    • ControlSource:设置文本框的数据来源。一般情况下,可以利用该属性为文本框指定一个字段或内存变量。

    • Value:保存文本框的当前内容,如果没有为ControlSource属性指定数据源,可以通过该属性访问文本框的内容。他的处置决定文本框中的类型。如果为ControlSource属性指定了数据源,该属性值与ControlSource属性指定的变量或字段的值相同。

    • PasswordChar:设置输入口令是显示的字符。

    • Readonly:确定文本框是否为只读,为T时,文本之不可修改。

命令按钮(CommandButton)控件和编辑框(EditBox)控件

  1. 命令按钮控件功能

    • 用来启动某个事件代码、完成特定功能。

  2. 命令按钮控件常用属性

    • Default:命令按钮的Default属性默认值为F,如果该属性设置为T,在该按钮所在的表单激活的情况下,按Enter,可以激活该按钮,并执行该按钮的Click事件代码。一个表单只能有一个按钮的Default属性为真。

    • Cancel:命令按钮的Cancel属性默认值为F,如果设置为T,在该案耨所在的表单激活的情况下,按Esc建可以激活该按钮,并执行该按钮的Click事件代码。一个表单只能有一个按钮的Cancel属性为真。

    • Caption:设置按钮的标题。

    • Enable:确定按钮是否有效,如果按钮的属性Enable为F,单击该按钮不会引发该按钮的单击事件。

  3. 编辑框控件的功能

    • 用于显示和编辑多行文本信息。在编辑框中能够选择、剪切、粘贴以及复制正文,可以实现自动换行,能够有自己的垂直滚动条。

  4. 编辑框常用属性

    • ControlSource:设置编辑框的数据源,一般为数据表的备注字段。

    • Value:保存编辑框中的内容,可以通过该属性来访问编辑框中的内容。

    • SelText:返回用户在编辑区内选定的文本,如果没有选定任何文本,则返回空串。

    • SelLength:返回用户在文本输入区中所选定字符的数目。

    • Readonly:确定用户是否能修改编辑框中的内容。

    • Scroolbars:指定编辑框是否具有滚动条,当属性值为0时,编辑框没有滚动条,当属性值为2(默认值)时,编辑框包含垂直滚动条。

选择组(OptionGroup)控件和列表框(ListBox)控件

  1. 选项组控件的功能

    • 是包含选项按钮的一种容器。一个选项组中往往包含若干个选项按钮,但用户只能从中选择一个按钮。当用户单击某个选项按钮时该按钮即成为备选中状态,而选项组中的其他选项按钮时,不管原来什么状态,都变为未选中状态,被选中的选项按钮中会显示一个圆点。

  2. 选项组常用属性

    • ButtonCount:指定选项组中选项按钮的数目。

    • Value:用于指定选项组中那个选项按钮被选中。

    • ControlSource:指定选项组数据源。

    • Buttons:用于存取选项组中每个选项的数组。

  3. 列表框的功能

    • 列表框提供一组条目(数据项),用户可以从中选择一个或多个条目,一般情况下,列表框显示其中的若干条目,用户可以通过滚动条浏览其他条目。

  4. 列表框常用属性

    • RowSourceType:指明列表框数据源的类型,可以为SQL语句、字段、别名、查询

    • RowSource:指定列表框的数据源

    • list属性:用以存取列表框中数据条目的字符串数组。

    • ListCount属性:列表框中数据条目的数目

    • ColumnCount属性:指定列表框的列数

    • Value属性:返回列表框中被选中的条目

    • ControlSource属性:将从列表框汇总选择的结果绑定指定的字段变量或内存变量上。

    • Selected属性:该属性是一个逻辑型数组,第n个数组元素代表第n个数据项是否为选定状态

    • MultiSelect属性:指定用户能否在列表框空间内进行多重选定(0或F不能,1或T允许,Ctrl+单击。)

  5. 列表框的常用方法

    • AddItem:把一个选项加入列表框

      • 格式:Control.AddItem(cltem[,nlndex] [,nColumn])

      • 其中cltem:是将要加入列表框的选项,必须是字符串表达式。

      • nlndex:指定数据项添加到列表框的位置。如果指定了有效的nlndex值,cltem将添加在列表框相应的位置处。

      • nColumn:指定控制的列,新数据项加入到此列中。

    • AddListltem:与与addltem类似,都是把一个列表项加入列表框中。只不过是addlistltem的参数是某个列表框的列表项,而不是字符串表达式。例如:

      • thisform.list2.addlistitem

      • (thisform.list1.listitem[1])

      • 将list1中第一个列表项添加到list2中

      • Clear:用于清除列表项中的所有列表项。

      • RemoveItem:用于删除列表框中的的列表项。

      • Index:被删除列表项在列表框中的序号。