R自动化生成报表里踩过的坑(一):R连Oracle

我们组不久前申请到了一台windows服务器,除了装了系统什么都没有,于是自己配置了一下R连Oracle,以及JAVA,因为不少R包要用到JAVA。此过程对我来说已经是颇为繁琐复杂了,还要配置环境变量这种我从来没听过的东西,总之最后不得已求助了开发哥哥才算配置成功了。这个过程略去不表,网上搜搜也是有不少教程的。

R自动化生成报表的思路是这样的,先用R连Oracle,从Oracle数据库里把前一天相关的所有数据都取出来,不做任何汇总操作。然后在R里处理数据,主要用data.table和dplyr两个包,做一些筛选和汇总。数据处理完了以后,在一个rmarkdown文件里用recharts包画图(如何使用recharts可以参考我前一篇博客),用DT包做表格,生成最后的报表。这样每天手动运行了一段时间后,用taskscheduleR包设置任务计划,每天定时自动运行。

虽然从Oracle里读取所有数据的时间较长,每天大约有70w行数据,但之后在R里进行数据处理和查询就比较方便快速。当然也可以在Oracle里写sql做汇总,然后用R读汇总数据,但因为我现在读的这个表索引做的不够好,在Oracle里做汇总本身也要花相当长的时间,比data.table要慢上许多。总之这个做法只是根据我的个人偏好和数据情况决定的。

好了,下面就一步步来说吧。

第一步,R连Oracle。

用的包是RODBC,64位windows,64位R 3.3.2,Rstudio 1.0.136,需要设置数据源(ODBC)。可以在网上搜一下,挺多教程的。如在这里配置了tuominku这个数据源。

ODBC数据源设置

RODBC包的基本使用方法是,先创建连接,tuominku就是前面创建的ODBC源,uid就是你访问这个数据库的用户名,pwd是对应的密码,都要放在引号里。

myconn <- RODBC::odbcConnect("tuominku",uid="uid",pwd="pwd") 

然后查询,用sqlQuery,把查询结果保存赋给data。

data<-RODBC::sqlQuery(myconn, "select * from table")

这里就有了第一个坑,就是中文乱码。 PL/SQL里查询中文正常显示,但是从R里读的就是中文乱码。在网上搜了一圈,都说要设置DBMSencoding为utf8,还有把system language设置成和oracle里一样的。那就这么设置吧

Sys.setenv(NLS_LANG="Simplified Chinese_china.AL32UTF8")
myconn <- RODBC::odbcConnect("tuominku",uid="uid",pwd="pwd",DBMSencoding="utf8", believeNRows=FALSE)

结果设置了以后还是不对,这就很郁闷了,R里的encoding也是utf-8,那怎么还是不对呢。终于发现(现在也忘了是怎么发现的了),utf8和utf-8是两个编码,具体有什么区别我也不清楚,但是在R里把encoding设置成utf8之后,中文就正常显示啦。

把R的encoding设置成utf8

另外提一句,上一段代码中的believeNRows=FALSE,虽然我没太搞清楚是什么意思,但它着实避免了一些报错,也没看到加上以后的坏处,所以就一直放着了。

这里就一起说下自己用RODBC的一些小心得。

  1. 在sql语句中使用R中的对象和函数:paste函数。
    最典型的应用是配合时间函数。如我做的日报,每天早上读取前一天的数据,手动去改时间就太麻烦了,也做不到完全自动化。本质上来说,sqlQuery函数中查询的就是引号里的一段文本,就可以用paste函数来生成,配合R里的Sys.Date函数。具体语法见下。还有一种方法是在sql里直接把时间变成系统时间的函数。
data<-RODBC::sqlQuery(myconn, 
paste("select * from table 
        where create_time between between to_date('", format(Sys.Date()-1,'%Y%m%d'), " 00:00:00', 'yyyymmdd hh24:mi:ss') 
        and to_date('", format(Sys.Date()-1,'%Y%m%d')," 23:59:59', 'yyyymmdd hh24:mi:ss')", 
        sep="")
  1. 数字以文本格式保存
    像会员号之类的一串数字,默认是以num格式读入的,如果很长的话就显示为科学计数法了。一个方法是设置科学计数法到很长的位数才使用:
options(scipen=200)

还有一个方法更为直接一点,在查询的时候就以文本保存,只要在sqlQuery中加入as.is=T即可,如:

data<-RODBC::sqlQuery(myconn, "select * from table", as.is=T)
  1. 把R中的dataframe保存到Oracle数据库的临时表中:sqlSave
    有时需要把R中清洗过的数据和Oracle中某些表关联,但这时候就不能像第一条中提到的用paste函数了,可以先将R中的dataframe存到数据库的临时表中,再用sql进行关联查询。
sqlSave(myconn, Rdataframe, tablename='TEMP1', rownames=FALSE, addPK=FALSE')

这里的Rdataframe就是在R中的dataframe,tablename是Oracle临时表的名字,切记一定要大写,否则无法查询,同时Rdataframe的column name也必须是大写。这可能是Oracle的限制吧,我没有仔细研究过。

  1. 通过R查询Oracle并将结果直接保存为临时表:sqlCopy
    对于一些复杂的报表需求,有时候需要创建临时表,减少同一段查询的次数,这时候如果先用sqlQuery将查询结果导出,再用sqlSave保存到Oracle临时表中,一读一存,写起来有点繁琐,这时就可以用sqlCopy直接将查询保存在临时表中,作用类似于create table。
sqlCopy(myconn,  'select * from table;', destination='TEST', verbose =T, errors = T)

但这里其实有一个bug,仍旧是字符型数字被当做科学计数法保存的问题,如一个18位的纯数字会员号,在表里是字符型的,如果直接通过sql查询也是字符型,但在通过sqlCopy则会变成数字型,即使定义这个字段的格式是文本型也不行。猜测这是因为sqlCopy的操作过程其实本质上仍是sqlQuery+sqlSave,而它确不提供第二条里提到的as.is选项。所以我现在不太使用sqlCopy,如果是要做create table as select..的操作,就直接在PL/SQL中先运行,或是在查询时前面加一个文本,如查询select "m"||customerid from table,之后再去掉m,最后一种方法就是用sqlQuery+sqlSave。

以上就是一些RODBC包使用中碰到过的问题和经验,还在不断地摸索中,欢迎交流~
下一篇讲taskscheduleR。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容