如何 select 所有非空列?
How to select all non-null columns?
我正在使用 R ODBC
包将查询发送到 VERTICA(SQL)
。我正在寻找一种快速解决方案,它将 select 来自 Table A 的所有非空列并将它们放入新的 table B。
我创建并运行了我认为效率极低的功能,但我不知道如何让它更快。如果 MAX
不为空,则该函数对 table 和 select 中的每一列取最大值。将所有内容放入一个查询中不会有太大变化,因为 Vertica
是一个列数据库。
reduce_width <- function(in_name, out_name) {
query_in <- paste('SELECT * FROM', in_name, 'LIMIT 1;', sep = ' ')
vertica_answer <- dbGetQuery(conn, query_in)
var_names <- colnames(vertica_answer)
lenght <- length(var_names)
var_names <- as.data.frame(var_names, stringsAsFactors = F)
var_names$is_null <- 0
for(i in 1:lenght){
name <- as.character(var_names[i,1])
query_max <- paste('SELECT MAX(',name,') from', in_name,';', sep = ' ')
max_value <- dbGetQuery(conn, query_max)
if(is.na(max_value[1,1])){
var_names$is_null[i]<-0
} else {
var_names $is_null[i]<-1
}
}
not_null_collumns <-var_names %>% filter(is_null==1) %>% select(var_names)
not_null_collumns <- (as.character(t(not_null_collumns$var_names)))
query_front <- 'SELECT'
for(i in 1:(length(not_null_collumns)-1)) {
query_front <- paste(query_front, not_null_collumns[i],',', sep = ' ')
}
query_front <- paste(query_front,
not_null_collumns[length(not_null_collumns)], sep = ' ')
query_back <- paste('into', out_name, 'from', in_name , sep = ' ')
query_create <- paste(query_front, query_back, sep = ' ')
dbSendQuery(conn, query_create)
}
如何使我的解决方案更快?
这里似乎有两个独立的部分:
1) 构建 SELECT 列表
您可以在脚本或存储过程/函数中执行此操作,但我认为这不会对性能产生太大影响。
2) 检查列是否有 NULL 值
这是对性能影响最大的地方。有几个想法可以尝试:
一些数据库在其数据字典中存储列是否为 NULLable
。您可以使用它来过滤掉 NULLable 列。链接:Oracle, Teradata
尝试另一种计算而不是 MAX
。也许 COUNT
会更快,因为它不必对值进行排序/比较。逻辑是这样的:
CASE
WHEN (
COALESCE(COUNT(*), 0) - -- Get total row count
COALESCE(COUNT(col1), 0) -- Get # non-NULL values in col1
) = 0 THEN 'No Nulls'
ELSE 'Has Nulls'
END AS col1_NullValuesCheck
您可以进行一次 COUNT(*)
计算,存储它并将其与 COUNT(colX)
值进行比较。
- 使用
EXISTS
运算符:
SELECT EXISTS(SELECT 1 FROM MyTable WHERE col1 IS NULL)
我同意之前发帖者的观点,将其合并为一个查询可能会更好。
你应该一次查询:
query_all <- paste('SELECT * FROM', in_name, ';', sep = ' ')
vertica_answer <- dbGetQuery(conn, query_all)
Vertica_sub <- vertica_answer[ , colSums(is.na(vertica_answer)) == 0]
#or just non null columns
non_null_cols <- names(verica_answer)[colSums(is.na(vertica_answer)) == 0]
您已经在循环中查询数据。这样效率更高,因为每个查询都有开销 运行.
我正在使用 R ODBC
包将查询发送到 VERTICA(SQL)
。我正在寻找一种快速解决方案,它将 select 来自 Table A 的所有非空列并将它们放入新的 table B。
我创建并运行了我认为效率极低的功能,但我不知道如何让它更快。如果 MAX
不为空,则该函数对 table 和 select 中的每一列取最大值。将所有内容放入一个查询中不会有太大变化,因为 Vertica
是一个列数据库。
reduce_width <- function(in_name, out_name) {
query_in <- paste('SELECT * FROM', in_name, 'LIMIT 1;', sep = ' ')
vertica_answer <- dbGetQuery(conn, query_in)
var_names <- colnames(vertica_answer)
lenght <- length(var_names)
var_names <- as.data.frame(var_names, stringsAsFactors = F)
var_names$is_null <- 0
for(i in 1:lenght){
name <- as.character(var_names[i,1])
query_max <- paste('SELECT MAX(',name,') from', in_name,';', sep = ' ')
max_value <- dbGetQuery(conn, query_max)
if(is.na(max_value[1,1])){
var_names$is_null[i]<-0
} else {
var_names $is_null[i]<-1
}
}
not_null_collumns <-var_names %>% filter(is_null==1) %>% select(var_names)
not_null_collumns <- (as.character(t(not_null_collumns$var_names)))
query_front <- 'SELECT'
for(i in 1:(length(not_null_collumns)-1)) {
query_front <- paste(query_front, not_null_collumns[i],',', sep = ' ')
}
query_front <- paste(query_front,
not_null_collumns[length(not_null_collumns)], sep = ' ')
query_back <- paste('into', out_name, 'from', in_name , sep = ' ')
query_create <- paste(query_front, query_back, sep = ' ')
dbSendQuery(conn, query_create)
}
如何使我的解决方案更快?
这里似乎有两个独立的部分:
1) 构建 SELECT 列表
您可以在脚本或存储过程/函数中执行此操作,但我认为这不会对性能产生太大影响。
2) 检查列是否有 NULL 值
这是对性能影响最大的地方。有几个想法可以尝试:
一些数据库在其数据字典中存储列是否为
NULLable
。您可以使用它来过滤掉 NULLable 列。链接:Oracle, Teradata尝试另一种计算而不是
MAX
。也许COUNT
会更快,因为它不必对值进行排序/比较。逻辑是这样的:
CASE
WHEN (
COALESCE(COUNT(*), 0) - -- Get total row count
COALESCE(COUNT(col1), 0) -- Get # non-NULL values in col1
) = 0 THEN 'No Nulls'
ELSE 'Has Nulls'
END AS col1_NullValuesCheck
您可以进行一次 COUNT(*)
计算,存储它并将其与 COUNT(colX)
值进行比较。
- 使用
EXISTS
运算符:
SELECT EXISTS(SELECT 1 FROM MyTable WHERE col1 IS NULL)
我同意之前发帖者的观点,将其合并为一个查询可能会更好。
你应该一次查询:
query_all <- paste('SELECT * FROM', in_name, ';', sep = ' ')
vertica_answer <- dbGetQuery(conn, query_all)
Vertica_sub <- vertica_answer[ , colSums(is.na(vertica_answer)) == 0]
#or just non null columns
non_null_cols <- names(verica_answer)[colSums(is.na(vertica_answer)) == 0]
您已经在循环中查询数据。这样效率更高,因为每个查询都有开销 运行.