使用 R 从 SQL 服务器导入数据截断前导零
Importing data using R from SQL Server truncate leading zeros
我正在尝试从 SQL 服务器中的 table 导入数据,然后将其写入 .txt
文件。我正在按以下方式进行。但是,当我这样做时,所有前导 0 的数字似乎都被修剪了。
例如,如果我在数据库中有 000124
,它在 .txt
中显示为 124
以及如果我检查 x_1 它在那里是 124嗯。
我怎样才能避免这种情况?我想在 x_1 中保留前导 0 并且在输出 .txt 文件中也需要它们。
library(RODBC)
library(lubridate)
library(data.table)
cn_1 <- odbcConnect('channel_name')
qry <- "
select
*
from table_name
"
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE)
rm(qry)
setDT(x_1)
fwrite(x=x_1, file=paste0(export_location, "file_name", date_today, ".txt"), sep="|", quote=TRUE, row.names=FALSE, na="")
让 x_1
成为您 SQL 查询的结果 data.table。然后,您可以使用 sprintf
将数字列(例如 value
)转换为格式化字符串以获得前导零:
library(data.table)
x_1 <- data.table(value = c(1,12,123,1234))
x_1
#> value
#> 1: 1
#> 2: 12
#> 3: 123
#> 4: 1234
x_1$value <- x_1$value |> sprintf(fmt = "%04d")
x_1
#> value
#> 1: 0001
#> 2: 0012
#> 3: 0123
#> 4: 1234
由 reprex package (v2.0.1)
于 2021-10-08 创建
假设 DBMS 中的基础数据确实是类似“字符串”的...
RODBC::sqlQuery
有 as.is=
参数可以防止它尝试转换值。默认值为 FALSE
,当 false 且不是像 "date"
或 "timestamp"
这样的明确类型时,RODBC 调用 type.convert
将看到类似数字的字段并将其转换为整数或数字。
尝试:
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = TRUE)
这将停止所有列的自动转换。
老实说,这有点核,并且会停止 dates/times 的转换,也许 应该 转换的其他列。我们可以缩小范围; ?sqlQuery
说 read.table
关于 as.is
的文档是相关的,它说:
as.is: controls conversion of character variables (insofar as they
are not converted to logical, numeric or complex) to factors,
if not otherwise specified by 'colClasses'. Its value is
either a vector of logicals (values are recycled if
necessary), or a vector of numeric or character indices which
specify which columns should not be converted to factors.
所以如果您知道哪个列(按名称或列索引)被不必要地转换,那么您可以直接包含它。也许
## by column name
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = "somename")
## or by column index
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = 7)
(旁注:虽然我有时也会使用 select * ...
,但按编号知道列的假设是基于知道 table/query 中包含的所有列。如果有任何变化,也许它实际上是一个 SQL 视图并且有人更新了它......或者如果有人更改了列的顺序,那么你对列索引的假设有点脆弱。我内部包中的所有“生产”查询都有所有列都拼写出来了,没有使用 select *
。我 使用它时被咬过一次,这就是为什么我对此有点防御。)
如果您不知道,一种仓促动态的方式(不幸的是双击查询)可能类似于
qry10 <- "
select
*
from table_name
limit 10"
x_1 <- sqlQuery(channel=cn_1, query=qry10, stringsAsFactors=FALSE, as.is = TRUE)
leadzero <- sapply(x_1, function(z) all(grepl("^0+[1-9]", z)))
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = which(leadzero))
警告:我不使用 RODBC
也没有设置具有适当时尚值的临时数据库,因此未经测试。
我正在尝试从 SQL 服务器中的 table 导入数据,然后将其写入 .txt
文件。我正在按以下方式进行。但是,当我这样做时,所有前导 0 的数字似乎都被修剪了。
例如,如果我在数据库中有 000124
,它在 .txt
中显示为 124
以及如果我检查 x_1 它在那里是 124嗯。
我怎样才能避免这种情况?我想在 x_1 中保留前导 0 并且在输出 .txt 文件中也需要它们。
library(RODBC)
library(lubridate)
library(data.table)
cn_1 <- odbcConnect('channel_name')
qry <- "
select
*
from table_name
"
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE)
rm(qry)
setDT(x_1)
fwrite(x=x_1, file=paste0(export_location, "file_name", date_today, ".txt"), sep="|", quote=TRUE, row.names=FALSE, na="")
让 x_1
成为您 SQL 查询的结果 data.table。然后,您可以使用 sprintf
将数字列(例如 value
)转换为格式化字符串以获得前导零:
library(data.table)
x_1 <- data.table(value = c(1,12,123,1234))
x_1
#> value
#> 1: 1
#> 2: 12
#> 3: 123
#> 4: 1234
x_1$value <- x_1$value |> sprintf(fmt = "%04d")
x_1
#> value
#> 1: 0001
#> 2: 0012
#> 3: 0123
#> 4: 1234
由 reprex package (v2.0.1)
于 2021-10-08 创建假设 DBMS 中的基础数据确实是类似“字符串”的...
RODBC::sqlQuery
有 as.is=
参数可以防止它尝试转换值。默认值为 FALSE
,当 false 且不是像 "date"
或 "timestamp"
这样的明确类型时,RODBC 调用 type.convert
将看到类似数字的字段并将其转换为整数或数字。
尝试:
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = TRUE)
这将停止所有列的自动转换。
老实说,这有点核,并且会停止 dates/times 的转换,也许 应该 转换的其他列。我们可以缩小范围; ?sqlQuery
说 read.table
关于 as.is
的文档是相关的,它说:
as.is: controls conversion of character variables (insofar as they
are not converted to logical, numeric or complex) to factors,
if not otherwise specified by 'colClasses'. Its value is
either a vector of logicals (values are recycled if
necessary), or a vector of numeric or character indices which
specify which columns should not be converted to factors.
所以如果您知道哪个列(按名称或列索引)被不必要地转换,那么您可以直接包含它。也许
## by column name
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = "somename")
## or by column index
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = 7)
(旁注:虽然我有时也会使用 select * ...
,但按编号知道列的假设是基于知道 table/query 中包含的所有列。如果有任何变化,也许它实际上是一个 SQL 视图并且有人更新了它......或者如果有人更改了列的顺序,那么你对列索引的假设有点脆弱。我内部包中的所有“生产”查询都有所有列都拼写出来了,没有使用 select *
。我 使用它时被咬过一次,这就是为什么我对此有点防御。)
如果您不知道,一种仓促动态的方式(不幸的是双击查询)可能类似于
qry10 <- "
select
*
from table_name
limit 10"
x_1 <- sqlQuery(channel=cn_1, query=qry10, stringsAsFactors=FALSE, as.is = TRUE)
leadzero <- sapply(x_1, function(z) all(grepl("^0+[1-9]", z)))
x_1 <- sqlQuery(channel=cn_1, query=qry, stringsAsFactors=FALSE, as.is = which(leadzero))
警告:我不使用 RODBC
也没有设置具有适当时尚值的临时数据库,因此未经测试。