读写MySQL

背景说明

很多时候我们要统计的目标数据并不存在于文本文件中,而往往是保存在数据库中,并且为了与展示程序做对接,最终的数据也需要写回到数据库中。 假设我们有如下一张存储了每天股票交易信息的数据表:

mysql> show create table rank_201507\G   
*************************** 1. row ***************************   
     Table: rank_201507   
Create Table: CREATE TABLE `rank_201507` (   
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   
  `collect_day` varchar(8) NOT NULL DEFAULT '' COMMENT '采集日期',   
  `collect_hour` varchar(2) NOT NULL DEFAULT '' COMMENT '采集时间点',   
  `board_name` varchar(20) NOT NULL DEFAULT '' COMMENT '排行榜名称',   
  `seq` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',   
  `stockid` varchar(20) NOT NULL DEFAULT '' COMMENT '股票代码',   
  `stock_name` varchar(100) NOT NULL DEFAULT '' COMMENT '股票名称',   
  `status` tinyint(4) NOT NULL DEFAULT '0',   
  `price` float NOT NULL DEFAULT '0' COMMENT '最新价',   
  `price_change` float NOT NULL DEFAULT '0' COMMENT '涨跌幅',   
  `trading_volume` int(11) NOT NULL DEFAULT '0' COMMENT '成交量(手)',   
  `trading_amount` float NOT NULL DEFAULT '0' COMMENT '成交额(万)',   
  `change_rate` int(11) NOT NULL DEFAULT '0',   
  `small_deal` int(11) NOT NULL DEFAULT '0' COMMENT '小单',   
  `medium_deal` int(11) NOT NULL DEFAULT '0' COMMENT '中单',   
  `big_deal` int(11) NOT NULL DEFAULT '0' COMMENT '大单',   
  `huge_deal` int(11) NOT NULL DEFAULT '0' COMMENT '超大单',   
  `exposure_amount` int(11) NOT NULL DEFAULT '0' COMMENT '历史媒体曝光量',   
  `exposure_amount_recent` int(11) NOT NULL DEFAULT '0',   
  `trend_up` int(11) NOT NULL DEFAULT '0' COMMENT '看涨数量',   
  `trend_down` int(11) NOT NULL DEFAULT '0' COMMENT '看跌数量',   
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE    CURRENT_TIMESTAMP COMMENT '记录更新时间',   
  PRIMARY KEY (`id`),
  UNIQUE KEY `hour_stock` (`collect_day`,`collect_hour`,`board_name`,`stockid`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=248381 DEFAULT CHARSET=utf8

mysql> select * from rank_201507 limit 1\G  
*************************** 1. row ***************************  
                  id: 1  
         collect_day: 20150701  
        collect_hour: 07  
          board_name: Raise  
                 seq: 1  
             stockid: sza-300231  
          stock_name: 银信科技  
              status: 1  
               price: 12.38  
        price_change: 10.04  
      trading_volume: 29731  
      trading_amount: 3639.45  
         change_rate: 0  
          small_deal: 524  
         medium_deal: -554  
            big_deal: -107  
           huge_deal: 137  
     exposure_amount: 175582  
exposure_amount_recent: 187  
            trend_up: 29731  
          trend_down: 5885  
         update_time: 2015-07-01 07:10:07  
1 row in set (0.06 sec)

现在要统计7月21日那一天大单数量超过50%的股票数据,并保存到新的数据表中stock_list中:

mysql> show create table stat.stock_list\G
*************************** 1. row ***************************
       Table: stock_list
Create Table: CREATE TABLE `stock_list` (
  `code` varchar(255) NOT NULL DEFAULT '',
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

问题分析

因为awk并没有jdbc的访问驱动,所以需要借助于mysql命令行的方式来完成数据的访问和写入。

解决方案

case_4-1.awk

# 定义数据库记录插入函数
function insertValue(code, name){  
    SQL_HEAD="/usr/bin/mysql -uroot -p123456 -e "
    TABLE_OP="insert ignore into stat.stock_list set "

    CODE = "code = \047"code"\047, "
    NAME = "name = \047"name"\047"
    comm = SQL_HEAD "\"" TABLE_OP "" CODE "" NAME "\"";
    print cmd;
    comm|getline result;
    close(comm);
}  

BEGIN{
    # 查询sql语句
    sql = "select stockid, stock_name, abs(small_deal), abs(medium_deal), abs(big_deal), abs(huge_deal) from stock.rank_201507 where collect_day = '20150721'";
    cmd = "/usr/bin/mysql -uroot -p123456 -N -e '" sql "'";

    # 使用mysql命令行执行
    while( cmd| getline > 0 ) {
            total = $3 + $4 + $5 + $6;
            # 判断条件满足插入数据库记录
            if ( total > 0 && $5/total > 0.5 ) {
                    print $1
                    insertValue($1, $2);
            }
    }
    close(cmd)
}

$awk -f case_4.awk

mysql> select * from stat.stock_list limit 10;
+------------+--------------+
| code       | name         |
+------------+--------------+
| sha-600301 | ST南化       |
| sha-600888 | 新疆众和     |
| sza-300236 | 上海新阳     |
| sha-601678 | 滨化股份     |
| sza-300353 | 东土科技     |
| sha-600066 | 宇通客车     |
| sha-600396 | 金山股份     |
| sza-002195 | 海隆软件     |
| sza-002327 | 富安娜       |
| sza-002246 | 北化股份     |
+------------+--------------+
10 rows in set (0.00 sec)

需要注意的有2点:

  1. 单引号“'”需要转义成\047;
  2. 注意BEGIN中的命令变量是cmd,函数insertValue()中的命令遍历是comm,这是因为awk中的变量都是全局的,如果都用成cmd就会导致在一次函数调用后因为原有管道被关闭而终止运行。

results matching ""

    No results matching ""