【问题标题】:Importing data using R from SQL Server truncate leading zeros使用 R 从 SQL Server 导入数据截断前导零
【发布时间】:2021-11-28 02:14:02
【问题描述】:

我正在尝试从 SQL Server 中的表导入数据,然后将其写入.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="")

【问题讨论】:

  • 数字没有前导零...只有字符串有。您需要确保在所有点都将其视为字符串以保持零。
  • @DaleK 是的。我想将这些字段视为字符串。我怎样才能确保我这样做。我应该在哪里更改代码。这就是我不确定的。

标签: sql r sql-server data.table leading-zero


【解决方案1】:

假设 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)

这将停止所有列的自动转换。

说实话,这有点核心,并且会停止日期/时间的转换,也许还有其他应该被转换的列。我们可以缩小范围; ?sqlQueryread.tableas.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 * ...,但按数字知道列的假设是基于知道该表/查询中包含的所有列。如果有任何变化,也许它实际上是一个 SQL查看并有人更新它...或者如果有人更改列的顺序,那么您对列索引的假设有点脆弱。我内部包中的所有“生产”查询都拼写了所有列,没有使用@987654334 @.我已经在使用的时候被咬过一次,所以我有点防备。)

如果您不知道,一种仓促的动态方式(不幸的是,双击查询)可能类似于

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,也没有设置具有适当时尚值的临时数据库,因此未经测试。

【讨论】:

    【解决方案2】:

    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 创建

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      相关资源
      最近更新 更多