【问题标题】:Remove Duplicate Columns via sqlQuery()通过 sqlQuery() 删除重复的列
【发布时间】:2022-01-14 17:49:36
【问题描述】:

我正在使用 R 编程语言。假设我有以下数据框:

age=18:29
height=c(76.1,77,78.1,78.2,78.8,79.7,79.9,81.1,81.2,81.8,82.8,83.5)
gender=c("M","F","M","M","F","F","M","M","F","M","F","M")
testframe = data.frame(age=age,height=height,height2=height,gender=gender,gender2=gender)

head(testframe)

  age height height2 gender gender2
1  18   76.1    76.1      M       M
2  19   77.0    77.0      F       F
3  20   78.1    78.1      M       M
4  21   78.2    78.2      M       M
5  22   78.8    78.8      F       F
6  23   79.7    79.7      F       F

如果我想删除名称不同但值相同的列,可以使用以下代码行:

no_dup = testframe[!duplicated(as.list(testframe))]

 head(no_dup)
  age height gender
1  18   76.1      M
2  19   77.0      F
3  20   78.1      M
4  21   78.2      M
5  22   78.8      F
6  23   79.7      F

我的问题:假设数据框不在全局环境中——是否可以通过sqlQuery() 命令传递上述代码行?例如:

library(RODBC)
library(sqldf)

con = odbcConnect("some name", uid = "some id", pwd = "abc")

#not sure if this is correct?
sample_query = sqlQuery(con, "testframe[!duplicated(as.list(testframe))]")

有人可以告诉我怎么做吗?

谢谢!

【问题讨论】:

  • 如果要更改数据库中的数据,请使用 SQL,而不是 R 代码。 R 可以将 SQL 命令传递给数据库,但仍然使用 SQL 进行编码。如果您只是想在将 R 对象从数据库中取出后更改它,则忽略 SQL 位。你想做什么?
  • @Michael Dewar:谢谢你的回复!我想做第一个:将SQL命令传递给数据库,但我不知道该怎么做。我知道如何在 R 中做到这一点(正如我在问题中所展示的那样) - 但我不知道如何通过 R 在 SQL 中做到这一点。你能告诉我如何做到这一点吗?谢谢!
  • 有趣的问题...我不知道SQL提供了一种简单的机制来动态选择列;我找到的方法(mssql1mssql2psql)创建一个查询字符串然后执行它,通常需要特定于 DBMS 的语言(t-sql 或存储过程)。除非它是大量数据,否则我认为在下载所有列之后在 R 中执行起来要简单得多。

标签: sql r duplicates odbc data-manipulation


【解决方案1】:

在 SQL 端进行所有实质性处理,并且只在 R 端进行名称操作。数据库未下载到 R。

第一个管道输入名称(我们在 Names 中对名称进行了硬编码,但如有必要,您可以从数据库中检索它们)并返回一条 SQL 语句 sql1,当针对您的数据库运行时,该语句将生成一个单行数据框来自数据库,该数据库对于 testframe 中的每对变量都有一列,其值是不相等值的数量。

然后我们使用 sqldf 运行 sql1 以获得可重复性,但您可以将其替换为对 sqlQuery 的适当调用。

然后,第二个管道使用 numDF 在字符向量 sql2 中生成一个或多个 SQL 语句,以删除重复的列,即那些有零个不相等值的列,然后您可以针对您的数据库运行这些 SQL 语句。

我们将 sqldf 与 SQLite 一起使用以实现可重复性,但您可以将对 sqldf 的调用替换为对 sqlQuery 的适当修改的调用,例如sqlQuery(con, sql1) 其中 con 是您之前定义的连接。

您使用的任何数据库系统都可能接受相同的 SQL,但如果不是,则代码中可能需要进行一些小的更改才能生成您正在使用的任何数据库系统接受的 SQL。

library(magrittr)
library(sqldf)

Names <- c("age", "height", "height2", "gender", "gender2")

sql1 <- Names %>%
  { toString(sprintf("sum(%s)", combn(., 2, paste, collapse = "!="))) } %>%
  paste("select", ., "from testframe")

numDF <- sqldf(sq11)  # replace with call to your database

sql2 <- numDF %>%
  Filter(Negate(c), .) %>%
  names %>%
  sub(".*!=(.*.).", "alter table testframe drop \\1", .)

# Just run the sql2 part against your db, not select * ... part.
# The select * ... downloads table for demo purposes only.
sqldf(c(sql2, "select * from testframe"))  # replace 
##    age height gender
## 1   18   76.1      M
## 2   19   77.0      F
## 3   20   78.1      M
## 4   21   78.2      M
## ...snip...

请注意,sql1 和 sql2 如下。 sql1 是单个 sql select 语句,sql2 是 sql alter 语句的向量,每列删除一个语句。如果您的数据库允许 ALTER 一次删除多个列,您也许可以简化这一点,但 SQLite 一次只允许一个。

sql1
## [1] "select sum(age!=height), sum(age!=height2), sum(age!=gender), sum(age!=gender2), sum(height!=height2), sum(height!=gender), sum(height!=gender2), sum(height2!=gender), sum(height2!=gender2), sum(gender!=gender2) from testframe"

sql2
## [1] "alter table testframe drop height2" "alter table testframe drop gender2"

【讨论】:

  • @G. Grothendieck:非常感谢您的回答!您能否解释一下“我们将 sqldf 与 SQLite 一起使用以实现可重复性,但您可以将对 sqldf 的调用替换为对 sqlQuery 的适当修改的调用。”您的意思是什么?你到底用什么“#replace this line”?
  • 这是你的意思吗? sample_query = sqlQuery(con, "numDF")
  • 到底这行代码是在本地运行,还是在服务器上运行? numDF % { toString(sprintf("sum(%s)", combn(., 2, paste, collapse = "!="))) } %>% paste("select", ., " from testframe") %>% sqldf # 替换这一行
  • 非常感谢您的帮助!
  • 添加了一些说明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-13
  • 2022-09-28
  • 2016-04-29
  • 1970-01-01
  • 2020-06-18
  • 1970-01-01
相关资源
最近更新 更多