MySQL 主从同步

1. 利用 docker 实现 mysql 主从同步 / 读写分离

为了保证数据的完整和安全,mysql 设计了主从同步,一个挂掉还可以用另个。最近重构论坛,想来改成主从吧。担心失误,就先拿 docker 练练手。

通过本文实际你会操作到。

  1. mysql 的主从同步

  2. docker 镜像和容器的创建

  3. docker 容器间的数据传递

  4. mycat 入门

以下需要大于 100 的智商和 mysql 基础 docker 基础,linux 基础。

没有也没事,就是看着会有点吃力。

环境是 centos,mycat 是 1.6.docker 是 1.12.6

1.1 下载 mysql 镜像

docker pull mysql// ps:如果下载太慢,请添加腾讯源,依次执行echo "OPTIONS='--registry-mirror=https://mirror.ccs.tencentyun.com'" >> /etc/sysconfig/docker
systemctl daemon-reload
service docker restart

或者直接去阿里仓库下 https://dev.aliyun.com/search.html 把上面的 –registry-mirror=https://mirror.ccs.tencentyun.com 换成你的专属源就可以

下载完输入 docker images

REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
docker.io/mysql             latest              44a8e1a5c0b2        8 days ago          407 MB

1.2 利用 mysql 镜像,创建用于主从同步的两个新镜像

我们当前所在的服务器叫宿主服务器

我们要利用 docker 虚拟两个 docker 容器服务器,一个主服务器,一个从服务器。

1.2.1 创建 master(主) 和 slave(从) 两个文件夹

/usr/mysql/master/usr/mysql/slave

1.2.2 在 master 和 slave 文件夹下 创建 Dockerfile 内容为

FROM mysql
COPY my.cnf /etc/mysql/  
EXPOSE 3306CMD ["mysqld"]

1.2.3 在 master 文件夹下 创建 my.cnf 内容为

[mysqld]log-bin=mysql-bin    //[必须]启用二进制日志server-id=1          //[必须]服务器唯一ID,默认是1,一般取IP最后一段,这里看情况分配

1.2.4 在 slave 文件夹下 创建 my.cnf 内容为

[mysqld]log-bin=mysql-bin    //[必须]启用二进制日志server-id=2          //[必须]服务器唯一ID,默认是1,一般取IP最后一段,这里看情况分配

1.2.5 切换到 master 目录下构建 master/mysql 镜像

docker build -t master/mysql .

(命令最后有个.,不要忘记,代表当前目录)

1.2.6 然后切换到 slave 目录下构建 slave/mysql 镜像

docker build -t slave/mysql .

(命令最后有个.,不要忘记,代表当前目录)

1.2.7 查看是否创建成功

[root@VM_118_220_centos ~]# docker imagesREPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
slave/mysql                 latest              8c496048d7ba        About an hour ago   407 MB
master/mysql                latest              7be30b0b631b        2 hours ago         407 MB
docker.io/mysql             latest              44a8e1a5c0b2        8 days ago          407 MB

1.3 用镜像创建容器

docker run -p 3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=mysql -d master/mysqldocker run -p 3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=mysql -d slave/mysql

1.3.1 从这里开始,建议打开两个终端窗口,方便操作

master 终端执行

docker exec -it mysql-master bash
mysql -uroot -p

输入密码 mysql 进入到 mysql 环境

slave 终端执行

docker exec -it mysql-slave bash
mysql -uroot -p

输入密码 mysql 进入到 mysql 环境

1.4 mysql 主从配置

mysql 配置

1.4.1 在主容器 mysql 中输入以下命令:

mysql>GRANT REPLICATION SLAVE ON *.* TO 'user'@'192.168.99.100' IDENTIFIED BY 'mysql';(指定ip)
或者
mysql>GRANT REPLICATION SLAVE ON *.* to 'user'@'%' identified by 'mysql';(所有ip)

然后查看主容器数据库状态:

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+------------------+----------+--------------+------------------+-------------------+| mysql-bin.000003 |     1338 |              |                  |                   |+------------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)

记录 File 的值和 Position 的值。

下面要用到,到这里为止,主库千万不要再做任何操作,防止状态改变。

1.4.2 然后我们配置一下从库

查看 master/mysql 的对外端口号

docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
8d1e3b87d499        slave/mysql         "docker-entrypoint.sh"   2 hours ago         Up 2 hours          0.0.0.0:32769->3306/tcp   mysql-slave
980e5ea48152        master/mysql        "docker-entrypoint.sh"   2 hours ago         Up 2 hours          0.0.0.0:32768->3306/tcp   mysql-master

0.0.0.0:32768->3306/tcp 其中 32768 为 master 的端口

mysql>change master to
master_host='x.x.x.x',
master_user='user',
master_log_file='mysql-bin.000003',
master_log_pos=1201,
master_port=32768,
master_password='mysql';
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

master_host=’x.x.x.x’ // 这里填 master 主机 ip

master_log_file=’mysql-bin.000003’, // 这里填写 File 的值

master_log_pos=1338,// 这里填写 Position 的值。

mysql> start slave;// 启动从服务器复制功能

如果不小心配置错, 输入 mysql> stop slave; 然后重新录入一遍

mysql>change master to
master_host='x.x.x.x',
master_user='user',
master_log_file='mysql-bin.000003',
master_log_pos=1201,
master_port=32768,
master_password='mysql';

就可以了

1.5 检查主从连接状态

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: x.x.x.x
                  Master_User: user
                  Master_Port: 32768
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 1338
               Relay_Log_File: 8d1e3b87d499-relay-bin.000002
                Relay_Log_Pos: 1221
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1338
              Relay_Log_Space: 1435
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: cd327a00-5e18-11e7-98f7-0242ac110006
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

这两个必须是 Yes 为 No 或者 connect 说明没有连接上

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

1.6 测试主从连接

注意设置主从后,操作只能在 master 终端上,slave 上的操作不会同步到 master 上。

1.6.1 登陆 master 终端

mysql> create database sunhao;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+| Database           |+--------------------+| information_schema || mysql              || performance_schema || sunhao             || sys                |+--------------------+5 rows in set (0.00 sec)
mysql> use sunhao
Database changed
mysql>  create table sunhao(id int(3),name char(10));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into sunhao values(1,'xiaoshuai');
Query OK, 1 row affected (0.01 sec)
mysql> select * from sunhao;
+------+-----------+| id   | name      |
+------+-----------+
|    1 | xiaoshuai |+------+-----------+1 row in set (0.00 sec)

1.6.2 登陆 slave 服务器

mysql> show databases;
+--------------------+| Database           |+--------------------+| information_schema || mysql              || performance_schema || sunhao             || sys                |+--------------------+5 rows in set (0.00 sec)
mysql> use sunhao
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select * from sunhao;
+------+-----------+| id   | name      |
+------+-----------+
|    1 | xiaoshuai |+------+-----------+

1.6.3 如果主服务器已经存在应用数据,则在进行主从复制时,需要单独复制处理(注意此操作,如果对从服务器单独录入的数据,会被覆盖掉。):

这里我们做一次完整的测试

(1) 在主服务器数据库插入新的数据,并进行锁表操作,不让数据再进行写入动作

mysql> insert into sunhao values(2,'xiaoshuai');
Query OK, 1 row affected (0.01 sec)
mysql> select * from sunhao;                   
+------+-----------+| id   | name      |
+------+-----------+
|    1 | xiaoshuai ||    2 | xiaoshuai |
+------+-----------+
2 rows in set (0.00 sec)
mysql> FLUSH TABLES WITH READ LOCK;
mysql> show full processlist;

(2) 退出 mysql,用 mysqldump 备份数据文件到 / var/lib, 然后顺便多余的用 tar 打包一下玩。哈哈。

mysql> exit
Bye
root@980e5ea48152:/var/lib/mysql# mysqldump -u root -p  sunhao > /var/lib/sunhao.dump    Enter password: root@980e5ea48152:/var/lib# tar -zcvf ./sunhao.dump .tar  ./sunhao.dump

(3) 打开宿主服务器,复制 mysql 主服务器文件 sunhao.dump.tar。到宿主服务器

[root]# docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES8d1e3b87d499        slave/mysql         "docker-entrypoint.sh"   4 hours ago         Up 4 hours          0.0.0.0:32769->3306/tcp   mysql-slave980e5ea48152        master/mysql        "docker-entrypoint.sh"   4 hours ago         Up 4 hours          0.0.0.0:32768->3306/tcp   mysql-master
mkdir -p /var/mydata
docker cp 980e:/var/lib/sunhao.dump.tar /var/mydata/
cd /var/mydata
[root@VM_128_230_centos mydata]# lssunhao.dump.tar

解释: docker cp 980e:/var/lib/sunhao.dump.tar /var/mydata/

980e 是 980e5ea48152 的缩写。保证不重复简写就可以

980e:/var/lib/sunhao.dump.tar 意思就是选中的容器下面你的文件下的 sunhao.dump.tar 文件

/var/mydata/ 目标文件

(4) 在宿主主机上输入

[root]# docker cp /var/mydata/sunhao.dump.tar 8d1e3b87d49936414c0e91ffdc60a054e7f4ef8b15baee295350565519abba0e:/var/lib/

(5) 在从服务器上输入

root@8d1e3b87d499:/# cd /var/lib/root@8d1e3b87d499:/var/lib# tar -zcvf sunhao.dump.tar

(6) 在从服务器上输入

tar -zxvpf /var/lib/mysqlbak.sql.tar
mysql -uroot -pmysql sunhao < /var/lib/sunhao.dump;

如果写入成功, 这个时候就可以用 select 查询到数据。

(2) 取消主服务器数据库锁定

mysql> UNLOCK TABLES;

错误:net/http: TLS handshake timeout;解决方案

docker pull 错误 net/http: TLS handshake timeout 的解决方案

问题原因 :该命令默认从docker远端镜像仓库中拉取镜像,但由于远端仓库的服务器是在国外,我们国内有的用户很可能都访问不

解决:使用国内镜像 daocloud镜像加速器

该方法需要配置加速器的镜像地址:register.mirror

Linux中使用命令:curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://d1d9aef0.m.daocloud.io  该脚本可以将 –registry-mirror 加入到你的 Docker 配置文件 /etc/docker/daemon.json 中。适用于 Ubuntu14.04、Debian、CentOS6 、CentOS7、Fedora、Arch Linux、openSUSE Leap 42.1,其他版本可能有细微不同

Windows中:在桌面右下角状态栏中右键 docker 图标,修改在 Docker Daemon 标签页中的 json ,把下面的地址:http://d1d9aef0.m.daocloud.io  加入到"registry-mirrors"的数组里。点击 Apply 。

MacOS中:右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中加入下面的镜像地址:http://d1d9aef0.m.daocloud.io 点击 Apply & Restart 按钮使设置生效。

image.png

更多信息,可查看dacloud官网:https://www.daocloud.io/mirror#accelerator-doc

composer install 安装依赖时常出现的异常

composer install 安装依赖时出现异常,导致项目无法运行。下面简单记录一下其中 2 个比较频繁问题的解决办法。

 

问题 & 解决

1、unzip依赖

异常消息:Unzip with unzip command failed, falling back to ZipArchive class

大致解释:php-zip 扩展依赖 unzip 命令,无法解压归档的压缩文件,导致回滚到归档。

解决办法:安装 zip、unzip 命令和 php-zip 扩展

#centos (我用 php7.1,以它为例)
yum install zip unzip php7.1-zip
#ubuntu
apt-get install zip unzip php7.1-zip

 

2、proc_open依赖

异常消息:The Process class relies on proc_open, which is not available on your PHP installation

大致解释:在已安装的 php 中,没有找到可用的 proc_open 进程操作函数。

解决办法:修改 php.ini 配置。把 disable_functions(禁用函数列表)这行里的 proc_open 函数删除,然后重启 PHP 服务。

#使用宝塔面板的朋友请打开【软件管理】->【PHP7.1】->【设置】->【禁用函数】列表,删除列表中的 "proc_open" 条目。

nex magration check

#status check
#######################################
select count(*), sum(voucher_value), b.status_desc from nex_evox_live.voucher a, nex_evox_live.voucher_lkup_status b 
where a.is_evoucher = 'Y' and a.status_id = b.status_id group by a.status_id;
#11979410Floating
#664952245Reimbursed
select count(*), sum(voucher_value), b.status_desc from nex_vms_live.voucher a, nex_vms_live.voucher_lkup_status b  
where a.is_evoucher = 'Y' and a.status_id = b.status_id group by a.status_id;
#11979410Issued
#573645765Reimbursed
#913  6480Tenant Submitted
#Stock check
#######################################
select count(*), sum(voucher_value), b.stock_desc from nex_evox_live.voucher a, nex_evox_live.voucher_lkup_stock b 
where a.is_evoucher = 'Y' and a.stock_id = b.stock_id group by a.stock_id;
#11979410Floating
#664952245Reimbursed
select count(*), sum(voucher_value), b.stock_desc from nex_vms_live.voucher a, nex_vms_live.voucher_lkup_stock b  
where a.is_evoucher = 'Y' and a.stock_id = b.stock_id group by a.stock_id;
#11979410Issued
#573645765Reimbursed
#913  6480Tenant Submitted
#action check
#######################################
select count(*), sum(voucher_value), b.action_id, c.action_desc
from nex_evox_live.voucher a, nex_evox_live.voucher_action b, nex_evox_live.voucher_lkup_action c
where a.is_evoucher = 'Y' and a.voucher_id = b.voucher_id and b.action_id = c.action_id
group by b.action_id;
#7846616551  Order
#78466165520  Stock In
#78466165570  Release
#78466165580  Allocation
#784661655150Direct Issue
#664952245180Reimburse
select count(*), sum(voucher_value), b.action_id, c.action_desc
from nex_vms_live.voucher a, nex_vms_live.voucher_action b, nex_vms_live.voucher_lkup_action c
where a.is_evoucher = 'Y' and a.voucher_id = b.voucher_id and b.action_id = c.action_id
group by b.action_id;
#7846616551  Create
#78466165530  Direct Issue
#66495224560  Tenant Submit
#57364576561  Reimburse
#374731810130Extend
#campaign check
#######################################
select campaign_id, campaign_code, campaign_desc from nex_evox_live.voucher_campaign where is_evoucher_campaign = 'Y'
#99Reward E-Voucher RedemptionReward E-Voucher Redemption
#100PJ MASKS SAVE CHRISTMAS @ NEXRECEIVE $10 ENEXVOUCHER WHEN YOU CHARGE $250 TO YOUR CITI CREDIT CARD AT PARTICIPATING STORES
#101PROSPEROUS ABUNDANCE @ NEX 2020RECEIVE $10 ENEXVOUCHER WHEN YOU CHARGE $250 TO YOUR CITI CREDIT CARD AT PARTICIPATING STORES
select campaign_id, campaign_code, campaign_desc from nex_vms_live.voucher_campaign where is_evoucher_campaign = 'Y'
#5  Reward E-Voucher RedemptionReward E-Voucher Redemption
#32PJ MASKS SAVE CHRISTMAS @ NEXRECEIVE $10 ENEXVOUCHER WHEN YOU CHARGE $250 TO YOUR CITI CREDIT CARD AT PARTICIPATING STORES
#34PROSPEROUS ABUNDANCE @ NEX 2020RECEIVE $10 ENEXVOUCHER WHEN YOU CHARGE $250 TO YOUR CITI CREDIT CARD AT PARTICIPATING STORES
#issue record check
#######################################
select count(*) as cnt, sum(c.voucher_value) as total_value ,b.campaign_code 
from nex_evox_live.voucher_campaign_issue a, nex_evox_live.voucher_campaign b, nex_evox_live.voucher c ,nex_evox_live.voucher_action d
where b.is_evoucher_campaign = 'Y' and a.campaign_id = b.campaign_id 
and a.voucher_id = c.voucher_id
and a.is_deleted = 'N' and a.id = d.related_id and d.action_id = 150
group by a.campaign_id
#623345525Reward E-Voucher Redemption
#8298290PJ MASKS SAVE CHRISTMAS @ NEX
#7847840PROSPEROUS ABUNDANCE @ NEX 2020
select count(*) as cnt, sum(c.voucher_value) as total_value ,b.campaign_code 
from nex_vms_live.voucher_campaign_issue a, nex_vms_live.voucher_campaign b, nex_vms_live.voucher c, nex_vms_live.voucher_action d
where b.is_evoucher_campaign = 'Y' and a.campaign_id = b.campaign_id and a.voucher_id = c.voucher_id
and a.is_deleted = 'N' and a.id = d.related_id and d.action_id = 30
group by a.campaign_id
#623345525Reward E-Voucher Redemption
#8298290PJ MASKS SAVE CHRISTMAS @ NEX
#7847840PROSPEROUS ABUNDANCE @ NEX 2020
#request table issue check
#######################################
select sum(b.total_value) as total_value from nex_evox_live.voucher_request_approve a, nex_evox_live.voucher_batch_no_section b 
where a.batch_id = b.batch_id and a.request_action = 150 and from_stock=120
#6568890
select sum(b.total_value) as total_value from nex_vms_live.voucher_request_approve a, voucher_batch_no_section b 
where a.batch_id = b.batch_id and a.request_action = 30
#9175975
select count(*) from nex_evox_live.voucher_request_approve where request_action = 150 and from_stock=120 #7846
select count(*) from nex_vms_live.voucher_request_approve where request_action = 30 #7846
#use voucher issue table check issue
#######################################
select sum(c.total_value) as total_value from nex_evox_live.voucher_campaign a, nex_evox_live.voucher_issue b,nex_evox_live.voucher_batch_no_section c  
where a.is_evoucher_campaign = 'Y' and a.campaign_id = b.campaign_id and b.batch_id = c.batch_id
#61655
#use reimbursement & reimbursement details check reimbruse
#######################################
select count(*), sum(c.voucher_value) 
from nex_evox_live.voucher_reimbursement a, nex_evox_live.voucher_reimbursement_details b, nex_evox_live.voucher c
where a.is_evoucher='Y' and a.submission_id = b.submission_id and b.is_deleted = 'N ' and b.is_retained = 'N' and b.voucher_id = c.voucher_id
#664952245
select count(*), sum(c.voucher_value) 
from nex_vms_live.voucher_reimbursement a, nex_vms_live.voucher_reimbursement_details b, nex_vms_live.voucher c
where a.submission_id = b.submission_id and b.is_deleted = 'N ' and b.is_retained = 'N' and b.voucher_id = c.voucher_id
#664952245

merctus all voucher report

CREATE TEMPORARY TABLE IF NOT EXISTS  `_temp_all_voucher` (

              `id` int(11) unsigned NOT NULL AUTO_INCREMENT,

              `voucher_id` int(11) DEFAULT NULL,

              `voucher_no` varchar(80) DEFAULT NULL,

              `voucher_value` int(11) DEFAULT NULL,

              `type_id` int(11) DEFAULT NULL,

              `type_desc` varchar(20) DEFAULT NULL,

              `status_id` int(11) DEFAULT NULL,

              `status_desc` varchar(29) DEFAULT NULL,

              `expiry_date` date DEFAULT NULL,

              `submission_id` int(11) DEFAULT NULL,

              `submission_time` datetime DEFAULT NULL,

              `submission_user_id` int(11) DEFAULT NULL,

              `submission_by` varchar(100) DEFAULT NULL,

              `reimburse_id` int(11) DEFAULT NULL,

              `reimburse_time` datetime DEFAULT NULL,

              `reimburse_user_id` int(11) DEFAULT NULL,

              `reimburse_by` varchar(100) DEFAULT NULL,

              `is_retained` enum('Y','N') DEFAULT 'N',

              `retained_time` datetime DEFAULT NULL,

              `retained_user_id` int(11) DEFAULT NULL,

              `retained_by` int(11) DEFAULT NULL,

              `retained_remarks` varchar(100) DEFAULT NULL,

              `released_time` datetime DEFAULT NULL,

              `release_user_id` int(11) DEFAULT NULL,

              `released_by` varchar(100) DEFAULT NULL,

              `campaign_id` int(11) DEFAULT NULL,

              `campaign_code` varchar(200) DEFAULT NULL,

              `issue_time` datetime DEFAULT NULL,

              `issue_by` varchar(100) DEFAULT NULL,

              `issue_user_id` int(11) DEFAULT NULL,

              `storeId` int(11) DEFAULT NULL,

              `organization` varchar(100) DEFAULT NULL,

              `storeName` varchar(100) DEFAULT NULL,

              `unit` varchar(100) DEFAULT NULL,

              `void_user_id` int(11) DEFAULT NULL,

              `void_time` datetime DEFAULT NULL,

              `void_by` varchar(100) DEFAULT NULL,

              PRIMARY KEY (`id`),

              KEY `voucher_id` (`voucher_id`),

              KEY `type_id` (`type_id`),

              KEY `status_id` (`status_id`),

              KEY `submission_id` (`submission_id`),

              KEY `is_retained` (`is_retained`),

              KEY `campaign_id` (`campaign_id`),

              KEY `issue_user_id` (`issue_user_id`)

            ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

            

            

#insert all voucher in to temp table

INSERT INTO `_temp_all_voucher` (`id`, `voucher_id`, `voucher_no`, `voucher_value`, `type_id`, `type_desc`, `status_id`, `status_desc`, `expiry_date`, `submission_id`, `submission_time`, `reimburse_time`,`is_retained`, `campaign_id`, `campaign_code`) 

select NULL, voucher_id, concat(prefix, voucher_text, suffix) as voucher_no, voucher_value, type_id, NULL, status_id, NULL, expiry_date, NULL, NULL, NULL, NULL, NULL, NULL

from voucher;

CREATE temporary TABLE `_temp_err_voucher` (

  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,

  `voucher_id` int(11) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `voucher_id` (`voucher_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

#insert err record

INSERT INTO `_temp_err_voucher` (`voucher_id`) 

select a.voucher_id from voucher_reimbursement_details a, voucher_reimbursement_details b

where a.voucher_id = b.voucher_id

and a.is_retained = 'N' and b.is_retained = 'Y'

and a.is_deleted = 'N' and b.is_deleted = 'N';

#update type desc

update _temp_all_voucher a, voucher_lkup_type b

set a.type_desc = b.type_desc

where a.type_id = b.type_id; 

#update status desc

update _temp_all_voucher a, voucher_lkup_status b

set a.status_desc = b.status_desc

where a.status_id = b.status_id;

#except double submit get submission id & submit time

update _temp_all_voucher a, 

(

  select voucher_id, max(submission_id) as submission_id 

  from voucher_reimbursement_details 

  where is_deleted = 'N' and is_retained = 'N' 

  and voucher_id not in (select voucher_id from _temp_err_voucher) GROUP BY 1

) b, voucher_reimbursement c 

set a.submission_id = b.submission_id, a.submission_time = c.submit_time, a.reimburse_time = c.reimburse_time, a.reimburse_user_id = c.reimburse_user, a.submission_user_id = c.submit_user, a.reimburse_id = c.reimburse_id

where a.voucher_id = b.voucher_id and b.submission_id = c.submission_id;

#double submit get submission id & submit time

update _temp_all_voucher a, 

(

  select voucher_id,  submission_id  from voucher_reimbursement_details 

  where is_deleted='N' and is_retained = 'N' 

  and voucher_id in (select voucher_id from _temp_err_voucher)

) b, voucher_reimbursement c 

set a.submission_id = b.submission_id, a.submission_time = c.submit_time, a.reimburse_time = c.reimburse_time, a.reimburse_user_id = c.reimburse_user, a.submission_user_id = c.submit_user, a.reimburse_id = c.reimburse_id

where a.voucher_id = b.voucher_id and b.submission_id = c.submission_id; 

#pure retaind get submission id & submit time

update _temp_all_voucher a, 

(

  select voucher_id, submission_id from voucher_reimbursement_details where is_retained = 'Y' and is_deleted='N' 

  and voucher_id not in (select voucher_id from _temp_err_voucher)

) b, voucher_reimbursement c 

set a.submission_id = b.submission_id, a.submission_time = c.submit_time, a.reimburse_time = c.reimburse_time, a.reimburse_user_id = c.reimburse_user, a.submission_user_id = c.submit_user, a.reimburse_id = c.reimburse_id

where a.voucher_id = b.voucher_id and b.submission_id = c.submission_id; 

#update is_retained

update _temp_all_voucher a, voucher_reimbursement_details b 

set a.is_retained = b.is_retained

where a.voucher_id = b.voucher_id and a.submission_id = b.submission_id;

#update campaign id and campaign code

update _temp_all_voucher a, voucher_campaign_issue b, voucher_campaign c, voucher_action d

set a.campaign_id = c.campaign_id, a.campaign_code = c.campaign_code, a.issue_time = d.action_time, a.issue_user_id = d.user_id

where a.voucher_id = b.voucher_id and b.campaign_id = c.campaign_id  and b.voucher_id = d.voucher_id and d.action_id = 30

and b.is_deleted = 'N' and b.id = d.related_id;

#update issue user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.issue_by = b.user_name

where a.issue_user_id = b.user_id;

#update release action

update voucher_action a, voucher_reimbursement_details b, _temp_all_voucher c

set c.released_time = a.action_time, c.release_user_id = a.user_id

where a.action_id = 80 and a.voucher_id = b.voucher_id

and a.related_id = b.detail_id 

and b.is_deleted = 'N' 

and a.voucher_id = c.voucher_id;

#update release user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.released_by = b.user_name

where a.release_user_id= b.user_id;

#update retain action

update voucher_action a, voucher_reimbursement_details b, _temp_all_voucher c

set c.retained_time = a.action_time, c.retained_user_id = a.user_id, c.retained_remarks = a.remarks

where a.action_id = 70 and a.voucher_id = b.voucher_id

and a.related_id = b.detail_id 

and b.is_deleted = 'N' 

and a.voucher_id = c.voucher_id;

#update retain user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.retained_by = b.user_name

where a.retained_user_id = b.user_id;

#update submit user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.submission_by = b.user_name

where a.submission_user_id = b.user_id;

#update reimburse user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.reimburse_by = b.user_name

where a.reimburse_user_id = b.user_id;

#update store info

update _temp_all_voucher a, voucher_reimbursement b, store c

set a.storeId = c.storeId, a.organization = c.organization, a.storeName = c.storeName, a.unit = c.unit

where a.submission_id = b.submission_id and b.lease_out_id = c.storeId;

#update void action and user

update _temp_all_voucher a, voucher_action b 

set a.void_time = b.action_time, a.void_user_id = b.user_id

where b.action_id = 140 and a.voucher_id = b.voucher_id and a.status_id = 50;

#update void user

update _temp_all_voucher a, evo_central_config.customer_user b

set a.void_by = b.user_name

where a.void_user_id = b.user_id;

#drop TEMPORARY TABLE `_temp_all_voucher` 

#drop TEMPORARY TABLE `_temp_err_voucher` 

select 

        voucher_no as 'Voucher no', 

        voucher_value as 'Voucher Value', 

        IFNULL(type_desc, '') as 'Voucher Type', 

        IFNULL(status_desc, '') as 'Voucher Status', 

        IFNULL(expiry_date, '') as 'Expiry Date', 

        IFNULL(submission_id, '') as 'Submission ID', 

        IFNULL(submission_time, '') as 'Submission Date',

        IFNULL(is_retained, '') as 'Retained Y/N',

        IFNULL(campaign_code, '') as 'Campaign Code or Name', 

        IFNULL(issue_time, '') as 'Issued Date', 

        IFNULL(issue_by, '') as 'Issue By',

        IFNULL(reimburse_time, '') as 'Reimburse Date', 

        IFNULL(reimburse_by, '') as 'Reimburse By', 

        IFNULL(retained_time, '') as 'Retained Time', 

        IFNULL(retained_by, '') as 'Retained By',

        IFNULL(released_time, '') as 'Release Time',

        IFNULL(released_by, '') as 'Release By',

        IFNULL(storeId, '') as 'Store ID',

        IFNULL(organization, '') as 'Organization',

        IFNULL(storeName, '') as 'Store Name',

        IFNULL(unit, '') as 'Unit',

        IFNULL(void_time, '') as 'Void Time',

        IFNULL(void_by, '') as 'Void By'

        from _temp_all_voucher

        order by 1 asc;

​CSS3 知识点总结

边框:

    border-image 设置所有边框图像的速记属性。

    border-radius 一个用于设置所有四个边框- *-半径属性的速记属性

        border-radius 所有四个边角 border-*-*-radius 属性的缩写

        border-top-left-radius 定义了左上角的弧度

        border-top-right-radius 定义了右上角的弧度

        border-bottom-right-radius 定义了右下角的弧度

        border-bottom-left-radius 定义了左下角的弧度

    box-shadow 附加一个或多个下拉框的阴影

        box-shadow: h-shadow v-shadow blur spread color inset;

            h-shadow 必需的。水平阴影的位置。允许负值

            v-shadow 必需的。垂直阴影的位置。允许负值

            blur 可选。模糊距离

            spread 可选。阴影的大小

            color 可选。阴影的颜色。在CSS颜色值寻找颜色值的完整列表

            inset 可选。从外层的阴影(开始时)改变阴影内侧阴影

背景:

    background-image:支持多重背景图像。

        background-image: url(https://static.runoob.com/images/mix/54cf2365000140e600740095.jpg),

        url(https://static.runoob.com/images/mix/54cf238a0001728d00740095.jpg),

        url(https://static.runoob.com/images/mix/54cf23b60001fd9700740096.jpg);

        background-position: left top, 100px 0, 200px 0;

        background-repeat: no-repeat, no-repeat, no-repeat;

    background-size

    background-origin

    background-clip

渐变:

    background-image: linear-gradient(direction, color-stop1, color-stop2, …);

    从上到下:background-image: linear-gradient(#e66465, #9198e5);

    从左到右:background-image: linear-gradient(to right, red , yellow);

    从左上到右下:background-image: linear-gradient(to bottom right, red, yellow);

    角度:background-image: linear-gradient(angle, color-stop1, color-stop2);   (-90deg)

    多个颜色节点:background-image: linear-gradient(red, yellow, green);

    透明度:background-image: linear-gradient(to right, rgba(255,0,0,0), rgba(255,0,0,1));

    重复的线性渐变:background-image: repeating-linear-gradient(red, yellow 10%, green 20%);

    径向渐变:background-image: radial-gradient(shape size at position, start-color, …, last-color);

        background-image: radial-gradient(red 5%, yellow 15%, green 60%);

    设置形状:circle 或 ellipse

        background-image: radial-gradient(circle, red, yellow, green);

    不同尺寸大小关键字的使用

        closest-side

        farthest-side

        closest-corner

        farthest-corner

            background-image: radial-gradient(closest-side at 60% 55%, red, yellow, black);

            background-image: radial-gradient(farthest-side at 60% 55%, red, yellow, black);

    重复的径向渐变

        background-image: repeating-radial-gradient(red, yellow 10%, green 15%);

文本效果:

    hanging-punctuation 规定标点字符是否位于线框之外。

        none 不在文本整行的开头还是结尾的行框之外放置标签符号。

        first 标点附着在首行开始边缘之外。

        last 标点附着在首行结尾边缘之外。

        allow-end

        force-end

    punctuation-trim 规定是否对标点字符进行修剪。(任何主流浏览器都不支持punctuation-trim属性。)

    text-align-last 设置如何对齐最后一行或紧挨着强制换行符之前的行。

    text-emphasis 向元素的文本应用重点标记以及重点标记的前景色。

    text-justify 规定当 text-align 设置为 "justify" 时所使用的对齐方法。

    text-outline 规定文本的轮廓。

    text-overflow 规定当文本溢出包含元素时发生的事情。

    text-shadow 向文本添加阴影。

        text-shadow: 5px 5px 5px #FF0000;

    text-wrap 规定文本的换行规则。

    word-break 规定非中日韩文本的换行规则。

    word-wrap 允许对长的不可分割的单词进行分割并换行到下一行。

box-shadow: 10px 10px 5px #888888;

CSS3 字体

    font-family name 必需。规定字体的名称。

    src URL 必需。定义字体文件的 URL。

    font-stretch 可选。定义如何拉伸字体。默认是 "normal"。

        normal

        condensed

        ultra-condensed

        extra-condensed

        semi-condensed

        expanded

        semi-expanded

        extra-expanded

        ultra-expanded

    font-style 可选。定义字体的样式。默认是 "normal"。

        normal

        italic

        oblique

    font-weight 可选。定义字体的粗细。默认是 "normal"。

        normal

        bold

        100

        200

        300

        400

        500

        600

        700

        800

        900

    unicode-range unicode-range 可选。定义字体支持的 UNICODE 字符范围。默认是 "U+0-10FFFF"。

CSS3 2D 转换

    transform 适用于2D或3D转换的元素

    transform-origin 允许您更改转化元素位置

2D 转换方法

    matrix(n,n,n,n,n,n) 定义 2D 转换,使用六个值的矩阵。

    translate(x,y) 定义 2D 转换,沿着 X 和 Y 轴移动元素。

    translateX(n) 定义 2D 转换,沿着 X 轴移动元素。

    translateY(n) 定义 2D 转换,沿着 Y 轴移动元素。

    scale(x,y) 定义 2D 缩放转换,改变元素的宽度和高度。

    scaleX(n) 定义 2D 缩放转换,改变元素的宽度。

    scaleY(n) 定义 2D 缩放转换,改变元素的高度。

    rotate(angle) 定义 2D 旋转,在参数中规定角度。

    skew(x-angle,y-angle) 定义 2D 倾斜转换,沿着 X 和 Y 轴。

    skewX(angle) 定义 2D 倾斜转换,沿着 X 轴。

    skewY(angle) 定义 2D 倾斜转换,沿着 Y 轴。

3D 转换

    matrix3d(n,n,n,n,n,n,

    n,n,n,n,n,n,n,n,n,n) 定义 3D 转换,使用 16 个值的 4×4 矩阵。

    translate3d(x,y,z) 定义 3D 转化。

    translateX(x) 定义 3D 转化,仅使用用于 X 轴的值。

    translateY(y) 定义 3D 转化,仅使用用于 Y 轴的值。

    translateZ(z) 定义 3D 转化,仅使用用于 Z 轴的值。

    scale3d(x,y,z) 定义 3D 缩放转换。

    scaleX(x) 定义 3D 缩放转换,通过给定一个 X 轴的值。

    scaleY(y) 定义 3D 缩放转换,通过给定一个 Y 轴的值。

    scaleZ(z) 定义 3D 缩放转换,通过给定一个 Z 轴的值。

    rotate3d(x,y,z,angle) 定义 3D 旋转。

    rotateX(angle) 定义沿 X 轴的 3D 旋转。

    rotateY(angle) 定义沿 Y 轴的 3D 旋转。

    rotateZ(angle) 定义沿 Z 轴的 3D 旋转。

    perspective(n) 定义 3D 转换元素的透视视图。

CSS3 过渡

    transition 简写属性,用于在一个属性中设置四个过渡属性。

        transition: width 1s, height 1s, transform 2s, background 2s, color 1s;

    transition-property 规定应用过渡的 CSS 属性的名称。

    transition-duration 定义过渡效果花费的时间。默认是 0。

    transition-timing-function 规定过渡效果的时间曲线。默认是 "ease"。

        linear 规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。

        ease 规定慢速开始,然后变快,然后慢速结束的过渡效果(cubic-bezier(0.25,0.1,0.25,1))。

        ease-in 规定以慢速开始的过渡效果(等于 cubic-bezier(0.42,0,1,1))。

        ease-out 规定以慢速结束的过渡效果(等于 cubic-bezier(0,0,0.58,1))。

        ease-in-out 规定以慢速开始和结束的过渡效果(等于 cubic-bezier(0.42,0,0.58,1))。

        cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。

    transition-delay 规定过渡效果何时开始。默认是 0。

CSS3 动画

    @keyframes 规定动画。

    animation 所有动画属性的简写属性,除了 animation-play-state 属性。

        animation: name duration timing-function delay iteration-count direction fill-mode play-state;

    animation-name 规定 @keyframes 动画的名称。

    animation-duration 规定动画完成一个周期所花费的秒或毫秒。默认是 0。

    animation-timing-function 规定动画的速度曲线。默认是 "ease"。

        linear 动画从头到尾的速度是相同的。

        ease 默认。动画以低速开始,然后加快,在结束前变慢。

        ease-in 动画以低速开始。

        ease-out 动画以低速结束。

        ease-in-out 动画以低速开始和结束。

        cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中自己的值。可能的值是从 0 到 1 的数值。

    animation-fill-mode 规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。

    animation-delay 规定动画何时开始。默认是 0。

    animation-iteration-count 规定动画被播放的次数。默认是 1。

        n 一个数字,定义应该播放多少次动画

        infinite 指定动画应该播放无限次(永远)

    animation-direction 规定动画是否在下一周期逆向地播放。默认是 "normal"。

    animation-play-state 规定动画是否正在运行或暂停。默认是 "running"。

CSS3 多列

    column-count

    column-gap

    column-rule-style

    column-rule-width

    column-rule-color

    column-rule

    column-span

    column-width

CSS3 用户界面

    appearance 允许您使一个元素的外观像一个标准的用户界面元素

    box-sizing 允许你以适应区域而用某种方式定义某些元素

        content-box

            这是由 CSS2.1 规定的宽度高度行为。

            宽度和高度分别应用到元素的内容框。

            在宽度和高度之外绘制元素的内边距和边框。

        border-box

            为元素设定的宽度和高度决定了元素的边框盒。

            就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。

            通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。

        inherit 规定应从父元素继承 box-sizing 属性的值。

    icon 为创作者提供了将元素设置为图标等价物的能力。

    nav-down 指定在何处使用箭头向下导航键时进行导航

    nav-index 指定一个元素的Tab的顺序

    nav-left 指定在何处使用左侧的箭头导航键进行导航

    nav-right 指定在何处使用右侧的箭头导航键进行导航

    nav-up 指定在何处使用箭头向上导航键时进行导航

    outline-offset 外轮廓修饰并绘制超出边框的边缘

    resize 指定一个元素是否是由用户调整大小

CSS3 弹性盒子

    弹性盒子由弹性容器(Flex container)和弹性子元素(Flex item)组成。

    弹性容器通过设置 display 属性的值为 flex 或 inline-flex将其定义为弹性容器。

    弹性容器内包含了一个或多个弹性子元素。

    注意: 弹性容器外及弹性子元素内是正常渲染的。弹性盒子只定义了弹性子元素如何在弹性容器内布局。

    弹性子元素通常在弹性盒子内一行显示。默认情况每个容器只有一行。

    flex-direction:属性指定了弹性子元素在父容器中的位置。

        flex-direction: row | row-reverse | column | column-reverse

    justify-content:内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐。

        justify-content: flex-start | flex-end | center | space-between | space-around

        flex-start:弹性项目向行头紧挨着填充。这个是默认值。第一个弹性项的main-start外边距边线被放置在该行的main-start边线,而后续弹性项依次平齐摆放。

        flex-end:弹性项目向行尾紧挨着填充。第一个弹性项的main-end外边距边线被放置在该行的main-end边线,而后续弹性项依次平齐摆放。

        center:弹性项目居中紧挨着填充。(如果剩余的自由空间是负的,则弹性项目将在两个方向上同时溢出)。

        space-between:弹性项目平均分布在该行上。如果剩余空间为负或者只有一个弹性项,则该值等同于flex-start。否则,第1个弹性项的外边距和行的main-start边线对齐,而最后1个弹性项的外边距和行的main-end边线对齐,然后剩余的弹性项分布在该行上,相邻项目的间隔相等。

        space-around:弹性项目平均分布在该行上,两边留有一半的间隔空间。如果剩余空间为负或者只有一个弹性项,则该值等同于center。否则,弹性项目沿该行分布,且彼此间隔相等(比如是20px),同时首尾两边和弹性容器之间留有一半的间隔(1/2*20px=10px)。

    align-items: 设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式

        align-items: flex-start | flex-end | center | baseline | stretch

        flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界。

        flex-end:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。

        center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。

        baseline:如弹性盒子元素的行内轴与侧轴为同一条,则该值与'flex-start'等效。其它情况下,该值将参与基线对齐。

        stretch:如果指定侧轴大小的属性值为'auto',则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照'min/max-width/height'属性的限制。

    flex-wrap: 属性用于指定弹性盒子的子元素换行方式

        flex-wrap: nowrap|wrap|wrap-reverse|initial|inherit;

        nowrap – 默认, 弹性容器为单行。该情况下弹性子项可能会溢出容器。

        wrap – 弹性容器为多行。该情况下弹性子项溢出的部分会被放置到新行,子项内部会发生断行

        wrap-reverse -反转 wrap 排列。

    align-content: 属性用于修改 flex-wrap 属性的行为。类似于 align-items, 但它不是设置弹性子元素的对齐,而是设置各个行的对齐。

        align-content: flex-start | flex-end | center | space-between | space-around | stretch

        stretch – 默认。各行将会伸展以占用剩余的空间。

        flex-start – 各行向弹性盒容器的起始位置堆叠。

        flex-end – 各行向弹性盒容器的结束位置堆叠。

        center -各行向弹性盒容器的中间位置堆叠。

        space-between -各行在弹性盒容器中平均分布。

        space-around – 各行在弹性盒容器中平均分布,两端保留子元素与子元素之间间距大小的一半。

    order:弹性子元素属性

        <integer>:用整数值来定义排列顺序,数值小的排在前面。可以为负值。

    对齐:

    设置"margin"值为"auto"值,自动获取弹性容器中剩余的空间。所以设置垂直方向margin值为"auto",可以使弹性子元素在弹性容器的两上轴方向都完全居中。

    以下实例在第一个弹性子元素上设置了 margin-right: auto; 。 它将剩余的空间放置在元素的右侧

    完美的居中:

    使用弹性盒子,居中变的很简单,只想要设置 margin: auto; 可以使得弹性子元素在两上轴方向上完全居中

    align-self: 属性用于设置弹性元素自身在侧轴(纵轴)方向上的对齐方式

    align-self: auto | flex-start | flex-end | center | baseline | stretch

        auto:如果'align-self'的值为'auto',则其计算值为元素的父元素的'align-items'值,如果其没有父元素,则计算值为'stretch'。

        flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界。

        flex-end:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。

        center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。

        baseline:如弹性盒子元素的行内轴与侧轴为同一条,则该值与'flex-start'等效。其它情况下,该值将参与基线对齐。

        stretch:如果指定侧轴大小的属性值为'auto',则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照'min/max-width/height'属性的限制。

    flex: 属性用于指定弹性子元素如何分配空间。

        flex: auto | initial | none | inherit |  [ flex-grow ] || [ flex-shrink ] || [ flex-basis ]

            auto: 计算值为 1 1 auto

            initial: 计算值为 0 1 auto

            none:计算值为 0 0 auto

            inherit:从父元素继承

            [ flex-grow ]:定义弹性盒子元素的扩展比率。

            [ flex-shrink ]:定义弹性盒子元素的收缩比率。

            [ flex-basis ]:定义弹性盒子元素的默认基准值。

    display 指定 HTML 元素盒子类型。

    flex-direction 指定了弹性容器中子元素的排列方式

    justify-content 设置弹性盒子元素在主轴(横轴)方向上的对齐方式。

    align-items 设置弹性盒子元素在侧轴(纵轴)方向上的对齐方式。

    flex-wrap 设置弹性盒子的子元素超出父容器时是否换行。

    align-content 修改 flex-wrap 属性的行为,类似 align-items, 但不是设置子元素对齐,而是设置行对齐

    flex-flow flex-direction 和 flex-wrap 的简写

    order 设置弹性盒子的子元素排列顺序。

    align-self 在弹性子元素上使用。覆盖容器的 align-items 属性。

    flex 设置弹性盒子的子元素如何分配空间。

使用弹性盒子创建响应式页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        .flex-container {
            display: -webkit-flex;
            display: flex;
            -webkit-flex-flow: row wrap;
            flex-flow: row wrap;
            font-weight: bold;
            text-align: center;
        }
        .flex-container > * {
            padding: 10px;
            flex: 1 100%;
        }
        .main {
            text-align: left;
            background: cornflowerblue;
        }
        .header {background: coral;}
        .footer {background: lightgreen;}
        .aside1 {background: moccasin;}
        .aside2 {background: violet;}
        @media all and (min-width: 600px) {
            .aside { flex: 1 auto; }
        }
        @media all and (min-width: 800px) {
            .main    { flex: 3 0px; }
            .aside1 { order: 1; }
            .main    { order: 2; }
            .aside2 { order: 3; }
            .footer  { order: 4; }
        }
    </style>
</head>
<body>
<div class="flex-container">
    <header class="header">头部</header>
    <article class="main">
        <p>菜鸟教程 - 学的不仅是技术,更是梦想!菜鸟教程(www.runoob.com)提供了最全的编程技术基础教程, 介绍了HTML、CSS、Javascript、Python,Java,Ruby,C,PHP , MySQL等各种编程语言的基础知识。 同时本站中也提供了大量的在线实例,通过实例,您可以更好的学习编程。</p>
    </article>
    <aside class="aside aside1">边栏 1</aside>
    <aside class="aside aside2">边栏 2</aside>
    <footer class="footer">底部</footer>
</div>
</body>
</html>

CSS知识点总结

背景:

background-color

background-image: background-image:url('paper.gif');

background-repeat:

    repeat(默认)

    repeat-x(只有水平位置会重复背景图像)

    repeat-y(只有垂直位置会重复背景图像)

    no-repeat(background-image不会重复)

    inherit(指定background-repea属性设置应该从父元素继承)

background-attachment(背景图像是否固定或者随着页面的其余部分滚动:

    scroll    背景图片随着页面的滚动而滚动,这是默认的

    fixed    背景图片不会随着页面的滚动而滚动

    local    背景图片会随着元素内容的滚动而滚动

    initial    设置该属性的默认值

    inherit    指定 background-attachment 的设置应该从父元素继承

background-position

    left top

    left center

    left bottom

    right top

    right center

    right bottom

    center top

    center center

    center bottom    如果仅指定一个关键字,其他值将会是"center"

    x% y%    第一个值是水平位置,第二个值是垂直。左上角是0%0%。右下角是100%100%。如果仅指定了一个值,其他值将是50%。 。默认值为:0%0%

    xpos ypos    第一个值是水平位置,第二个值是垂直。左上角是0。单位可以是像素(0px0px)或任何其他 CSS单位。如果仅指定了一个值,其他值将是50%。你可以混合使用%和positions

    inherit    指定background-position属性设置应该从父元素继承

文本格式:

    text-align

        left 把文本排列到左边。默认值:由浏览器决定。

        right 把文本排列到右边。

        center 把文本排列到中间。

        justify 实现两端对齐文本效果。

        inherit 规定应该从父元素继承 text-align 属性的值。

字体:

    font 在一个声明中设置所有的字体属性

    font-family 指定文本的字体系列

    font-size 指定文本的字体大小

    font-style 指定文本的字体样式

    font-variant 以小型大写字体或者正常字体显示文本。

    font-weight 指定字体的粗细。

链接:

    a:link {text-decoration:none;}

    a:visited

    a:hover

    a:active

列表:

    list-style 简写属性。用于把所有用于列表的属性设置于一个声明中

    list-style-image 将图像设置为列表项标志。

    list-style-position 设置列表中列表项标志的位置。

    list-style-type 设置列表项标志的类型。

        circle

        square

        upper-roman

        low-alpha

    ul无序,ol有序

表格:

    border-collapse:collapse;

    caption、col、colgroup、thead、tfoot 以及 tbody 都是table的元素,属于html范畴。

vertical-align 属性:

    baseline 默认。元素放置在父元素的基线上。

    sub 垂直对齐文本的下标。

    super 垂直对齐文本的上标

    top 把元素的顶端与行中最高元素的顶端对齐

    text-top 把元素的顶端与父元素字体的顶端对齐

    middle 把此元素放置在父元素的中部。

    bottom 把元素的顶端与行中最低的元素的顶端对齐。

    text-bottom 把元素的底端与父元素字体的底端对齐。

    length

    % 使用 "line-height" 属性的百分比值来排列此元素。允许使用负值。

    inherit 规定应该从父元素继承 vertical-align 属性的值。

        对哪些元素可以使用Vertical-Align

        vertical-align用于对齐行内元素。所谓行内元素,即display属性值为下列之一的元素:

            inline

            inline-block

            inline-table

        其中,行内元素(inline element)就是包含文本的标签。

        而行内块元素(inline-block element),顾名思义,就是位于行内的块元素。可以有宽度和高度(可以由其内容决定),也可以有内边距、边框和外边距。

        https://blog.csdn.net/qq_43173244/article/details/83063501

边框:

    border 简写属性,用于把针对四个边的属性设置在一个声明。

    border-style 用于设置元素所有边框的样式,或者单独地为各边设置边框样式。

        dotted: 定义一个点线边框

        dashed: 定义一个虚线边框

        solid: 定义实线边框

        double: 定义两个边框。 两个边框的宽度和 border-width 的值相同

        groove: 定义3D沟槽边框。效果取决于边框的颜色值

        ridge: 定义3D脊边框。效果取决于边框的颜色值

        inset:定义一个3D的嵌入边框。效果取决于边框的颜色值

        outset: 定义一个3D突出边框。 效果取决于边框的颜色值

    border-width 简写属性,用于为元素的所有边框设置宽度,或者单独地为各边边框设置宽度。

    border-color 简写属性,设置元素的所有边框中可见部分的颜色,或为 4 个边分别设置颜色。

    border-bottom 简写属性,用于把下边框的所有属性设置到一个声明中。

    border-bottom-color 设置元素的下边框的颜色。

    border-bottom-style 设置元素的下边框的样式。

    border-bottom-width 设置元素的下边框的宽度。

    border-left 简写属性,用于把左边框的所有属性设置到一个声明中。

    border-left-color 设置元素的左边框的颜色。

    border-left-style 设置元素的左边框的样式。

    border-left-width 设置元素的左边框的宽度。

    border-right 简写属性,用于把右边框的所有属性设置到一个声明中。

    border-right-color 设置元素的右边框的颜色。

    border-right-style 设置元素的右边框的样式。

    border-right-width 设置元素的右边框的宽度。

    border-top 简写属性,用于把上边框的所有属性设置到一个声明中。

    border-top-color 设置元素的上边框的颜色。

    border-top-style 设置元素的上边框的样式。

    border-top-width 设置元素的上边框的宽度。

轮廓:

    outline 在一个声明中设置所有的轮廓属性

        outline-color

        outline-style

        outline-width

        inherit

    outline-color 设置轮廓的颜色

        color-name

        hex-number

        rgb-number

        invert

        inherit

    outline-style 设置轮廓的样式

        none

        dotted

        dashed

        solid

        double

        groove

        ridge

        inset

        outset

        inherit

    outline-width 设置轮廓的宽度

        thin

        medium

        thick

        length

        inherit

margin(外边距)

    margin 简写属性。在一个声明中设置所有外边距属性。

    margin-bottom 设置元素的下外边距。

    margin-left 设置元素的左外边距。

    margin-right 设置元素的右外边距。

    margin-top 设置元素的上外边距。

padding(填充)

    padding 使用简写属性设置在一个声明中的所有填充属性

    padding-bottom 设置元素的底部填充

    padding-left 设置元素的左部填充

    padding-right 设置元素的右部填充

    padding-top 设置元素的顶部填充

尺寸 (Dimension)

    height 设置元素的高度。

    line-height 设置行高。

    max-height 设置元素的最大高度。

    max-width 设置元素的最大宽度。

    min-height 设置元素的最小高度。

    min-width 设置元素的最小宽度。

    width 设置元素的宽度。

隐藏元素 – display:none或visibility:hidden

    visibility:hidden可以隐藏某个元素,但隐藏的元素仍需占用与未隐藏之前一样的空间。也就是说,该元素虽然被隐藏了,但仍然会影响布局。

    display:none可以隐藏某个元素,且隐藏的元素不会占用任何空间。也就是说,该元素不但被隐藏了,而且该元素原本占用的空间也会从页面布局中消失。

CSS display 属性

    none 此元素不会被显示。

    block 此元素将显示为块级元素,此元素前后会带有换行符。

    inline 默认。此元素会被显示为内联元素,元素前后没有换行符。

    inline-block 行内块元素。(CSS2.1 新增的值)

    list-item 此元素会作为列表显示。

    run-in 此元素会根据上下文作为块级元素或内联元素显示。

    compact CSS 中有值 compact,不过由于缺乏广泛支持,已经从 CSS2.1 中删除。

    marker CSS 中有值 marker,不过由于缺乏广泛支持,已经从 CSS2.1 中删除。

    table 此元素会作为块级表格来显示(类似 <table>),表格前后带有换行符。

    inline-table 此元素会作为内联表格来显示(类似 <table>),表格前后没有换行符。

    table-row-group 此元素会作为一个或多个行的分组来显示(类似 <tbody>)。

    table-header-group 此元素会作为一个或多个行的分组来显示(类似 <thead>)。

    table-footer-group 此元素会作为一个或多个行的分组来显示(类似 <tfoot>)。

    table-row 此元素会作为一个表格行显示(类似 <tr>)。

    table-column-group 此元素会作为一个或多个列的分组来显示(类似 <colgroup>)。

    table-column 此元素会作为一个单元格列显示(类似 <col>)

    table-cell 此元素会作为一个表格单元格显示(类似 <td> 和 <th>)

    table-caption 此元素会作为一个表格标题显示(类似 <caption>)

    inherit 规定应该从父元素继承 display 属性的值。

CSS visibility 属性

    visible 默认值。元素是可见的。

    hidden 元素是不可见的。

    collapse 当在表格元素中使用时,此值可删除一行或一列,但是它不会影响表格的布局。被行或列占据的空间会留给其他内容使用。如果此值被用在其他的元素上,会呈现为 "hidden"。

    inherit 规定应该从父元素继承 visibility 属性的值。

CSS Position(定位)

    bottom 定义了定位元素下外边距边界与其包含块下边界之间的偏移。

        auto

        length

        %

        inherit

    clip 剪辑一个绝对定位的元素

        shape – rect (top, right, bottom, left)

        auto

        inherit

    cursor 显示光标移动到指定的类型

        url 需使用的自定义光标的 URL。

        注释:请在此列表的末端始终定义一种普通的光标,以防没有由 URL 定义的可用光标。

        default 默认光标(通常是一个箭头)

        auto 默认。浏览器设置的光标。

        crosshair 光标呈现为十字线。

        pointer 光标呈现为指示链接的指针(一只手)

        move 此光标指示某对象可被移动。

        e-resize 此光标指示矩形框的边缘可被向右(东)移动。

        ne-resize 此光标指示矩形框的边缘可被向上及向右移动(北/东)。

        nw-resize 此光标指示矩形框的边缘可被向上及向左移动(北/西)。

        n-resize 此光标指示矩形框的边缘可被向上(北)移动。

        se-resize 此光标指示矩形框的边缘可被向下及向右移动(南/东)。

        sw-resize 此光标指示矩形框的边缘可被向下及向左移动(南/西)。

        s-resize 此光标指示矩形框的边缘可被向下移动(北/西)。

        w-resize 此光标指示矩形框的边缘可被向左移动(西)。

        text 此光标指示文本。

        wait 此光标指示程序正忙(通常是一只表或沙漏)。

        help 此光标指示可用的帮助(通常是一个问号或一个气球)。

    left 定义了定位元素左外边距边界与其包含块左边界之间的偏移。

        auto

        length

        %

        inherit

    overflow 设置当元素的内容溢出其区域时发生的事情。

        auto

        hidden

        scroll

        visible

        inherit

    overflow-y

    指定如何处理顶部/底部边缘的内容溢出元素的内容区域 auto

    hidden

    scroll

    visible

    no-display

    no-content

    overflow-x

    指定如何处理右边/左边边缘的内容溢出元素的内容区域 auto

    hidden

    scroll

    visible

    no-display

    no-content

    position 指定元素的定位类型

        absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。

        元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

        fixed

        生成固定定位的元素,相对于浏览器窗口进行定位。

        元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

        relative

        生成相对定位的元素,相对于其正常位置进行定位。

        因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。

        static 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。

        sticky

        粘性定位,该定位基于用户滚动的位置。

        它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。

        注意: Internet Explorer, Edge 15 及更早 IE 版本不支持 sticky 定位。 Safari 需要使用 -webkit- prefix (查看以下实例)。

        inherit 规定应该从父元素继承 position 属性的值。

        initial 设置该属性为默认值,详情查看 CSS initial 关键字。

    right 定义了定位元素右外边距边界与其包含块右边界之间的偏移。 auto

    length

    %

    inherit

    top 定义了一个定位元素的上外边距边界与其包含块上边界之间的偏移。 auto

    length

    %

    inherit

    z-index 设置元素的堆叠顺序 number

    auto

    inherit

CSS 布局 – Overflow

    visible 默认值。内容不会被修剪,会呈现在元素框之外。

    hidden 内容会被修剪,并且其余内容是不可见的。

    scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。

    auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。

    inherit 规定应该从父元素继承 overflow 属性的值。

CSS Float(浮动)

    clear 指定不允许元素周围有浮动元素。

        left

        right

        both

        none

    inherit

    float 指定一个盒子(元素)是否可以浮动。

        left

        right

        none

        inherit

CSS 布局 – 水平 & 垂直对齐

    注释:绝对定位元素会被从正常流中删除,并且能够交叠元素。

    提示: 当使用 position 来对齐元素时, 通常 <body> 元素会设置 margin 和 padding 。 这样可以避免在不同的浏览器中出现可见的差异。

    当使用 position 属性时,IE8 以及更早的版本存在一个问题。如果容器元素(在我们的案例中是 <div class="container">)设置了指定的宽度,并且省略了 !DOCTYPE 声明,那么 IE8 以及更早的版本会在右侧增加 17px 的外边距。这似乎是为滚动条预留的空间。当使用 position 属性时,请始终设置 !DOCTYPE 声明:

    绝对定位使用通常是父级定义position:relative定位,子级定义position:absolute绝对定位属性,并且子级使用left或right和top或bottom进行绝对定位

CSS 组合选择符

    后代选择器(以空格分隔)

    子元素选择器(以大于号分隔)

    相邻兄弟选择器(以加号分隔)

    普通兄弟选择器(以破折号分隔)

CSS 伪类(Pseudo-classes)

    a:link {color:#FF0000;} /* 未访问的链接 */

    a:visited {color:#00FF00;} /* 已访问的链接 */

    a:hover {color:#FF00FF;} /* 鼠标划过链接 */

    a:active {color:#0000FF;} /* 已选中的链接 */

CSS :first-child 伪类

您可以使用 :first-child 伪类来选择父元素的第一个子元素。

注意:在IE8的之前版本必须声明<!DOCTYPE> ,这样 :first-child 才能生效。

    :checked input:checked 选择所有选中的表单元素

    :disabled input:disabled 选择所有禁用的表单元素

    :empty p:empty 选择所有没有子元素的p元素

    :enabled input:enabled 选择所有启用的表单元素

    :first-of-type p:first-of-type 选择的每个 p 元素是其父元素的第一个 p 元素

    :in-range input:in-range 选择元素指定范围内的值

    :invalid input:invalid 选择所有无效的元素

    :last-child p:last-child 选择所有p元素的最后一个子元素

    :last-of-type p:last-of-type 选择每个p元素是其母元素的最后一个p元素

    :not(selector) :not(p) 选择所有p以外的元素

    :nth-child(n) p:nth-child(2) 选择所有 p 元素的父元素的第二个子元素

    :nth-last-child(n) p:nth-last-child(2) 选择所有p元素倒数的第二个子元素

    :nth-last-of-type(n) p:nth-last-of-type(2) 选择所有p元素倒数的第二个为p的子元素

    :nth-of-type(n) p:nth-of-type(2) 选择所有p元素第二个为p的子元素

    :only-of-type p:only-of-type 选择所有仅有一个子元素为p的元素

    :only-child p:only-child 选择所有仅有一个子元素的p元素

    :optional input:optional 选择没有"required"的元素属性

    :out-of-range input:out-of-range 选择指定范围以外的值的元素属性

    :read-only input:read-only 选择只读属性的元素属性

    :read-write input:read-write 选择没有只读属性的元素属性

    :required input:required 选择有"required"属性指定的元素属性

    :root root 选择文档的根元素

    :target #news:target 选择当前活动#news元素(点击URL包含锚的名字)

    :valid input:valid 选择所有有效值的属性

    :link a:link 选择所有未访问链接

    :visited a:visited 选择所有访问过的链接

    :active a:active 选择正在活动链接

    :hover a:hover 把鼠标放在链接上的状态

    :focus input:focus 选择元素输入后具有焦点

    :first-letter p:first-letter 选择每个<p> 元素的第一个字母

    :first-line p:first-line 选择每个<p> 元素的第一行

    :first-child p:first-child 选择器匹配属于任意元素的第一个子元素的 <p> 元素

    :before p:before 在每个<p>元素之前插入内容

    :after p:after 在每个<p>元素之后插入内容

    :lang(language) p:lang(it) 为<p>元素的lang属性选择一个开始值

CSS伪类/元素

    :link a:link 选择所有未访问链接

    :visited a:visited 选择所有访问过的链接

    :active a:active 选择正在活动链接

    :hover a:hover 把鼠标放在链接上的状态

    :focus input:focus 选择元素输入后具有焦点

    :first-letter p:first-letter 选择每个<p> 元素的第一个字母

    :first-line p:first-line 选择每个<p> 元素的第一行

    :first-child p:first-child 选择器匹配属于任意元素的第一个子元素的 <p> 元素

    :before p:before 在每个<p>元素之前插入内容

    :after p:after 在每个<p>元素之后插入内容

    :lang(language) p:lang(it) 为<p>元素的lang属性选择一个开始值

CSS 媒体类型

    all 用于所有的媒体设备。

    aural 用于语音和音频合成器。

    braille 用于盲人用点字法触觉回馈设备。

    embossed 用于分页的盲人用点字法打印机。

    handheld 用于小的手持的设备。

    print 用于打印机。

    projection 用于方案展示,比如幻灯片。

    screen 用于电脑显示器。

    tty 用于使用固定密度字母栅格的媒体,比如电传打字机和终端。

    tv 用于电视机类型的设备。

CSS 选择器

    [attribute] 用于选取带有指定属性的元素。

    [attribute=value] 用于选取带有指定属性和值的元素。

    [attribute~=value] 用于选取属性值中包含指定词汇的元素。

    [attribute|=value] 用于选取带有以指定值开头的属性值的元素,该值必须是整个单词。

    [attribute^=value] 匹配属性值以指定值开头的每个元素。

    [attribute$=value] 匹配属性值以指定值结尾的每个元素。

    [attribute*=value] 匹配属性值中包含指定值的每个元素。

merctus voucher summary report

#select min(issue_time) from voucher_issued_details_for_report 



set @start_time = '2020-05-01 00:00:00';
set @end_time = '2020-05-31 23:59:59';


#get opening 
select 
SUM( IF(issue_time < @start_time, voucher_value, 0 ))
- SUM( IF(reimburse_time < @start_time, voucher_value, 0 ))
- SUM( IF(void_time < @start_time, voucher_value, 0 )) AS 'Opening Floating',
SUM( IF(issue_time between @start_time and @end_time, voucher_value, 0 )) as issued,
SUM( IF(reimburse_time between @start_time and @end_time, voucher_value, 0 )) as reimbursed,
SUM( IF(void_time between @start_time and @end_time, voucher_value, 0 )) as void,
SUM( IF(expire_time between @start_time and @end_time, voucher_value, 0 )) as expired
from voucher_issued_details_for_report;

image.png

Merctus use snapshot table calculate voucher summary report

just a month Ex.

we can get pre month data and concat to a complate report.

                
#1.get every monthly data
set @start_time = '2020-04-01 00:00:00';
set @end_time = '2020-04-30 23:59:59';


SELECT voucher_id, voucher_value
#DATE_FORMAT(expire_time,'%Y%m') months, SUM(voucher_value) AS amount
FROM voucher_issued_details_for_report
WHERE expire_time >= @start_time AND expire_time <= @end_time
and issue_time <= @end_time
and (submit_time > @end_time or reimburse_time is null)
and (void_time > @end_time or void_time is null)


select * from voucher where voucher_id in (1036,1037,5261)
select * from  voucher_issued_details_for_report where voucher_id in (1036,1037,5261)