如何 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]

您已经在循环中查询数据。这样效率更高,因为每个查询都有开销 运行.