如何在MySQL中返回一个不合适的值列表

时间:2015-01-16 16:39:05

标签: mysql sql ruby

如何使用 colA 的值列表查询 table1 并返回未找到的值列表?

即。 all_values = [“a”,“b”,“c”,“d”]

Table1已经包含 colA 的行,用于“b”,“c”

我想创建一个查询,我可以在整个 all_values 列表中发送并返回 new_values = [“a”,“d”]

目前我必须首先获取所有 existing_values = SELECT colA FROM table1,然后执行 new_values = all_values - existing_values 。但是,如果 all_values 增长非常大,这可能是一个昂贵的例程。我想利用这里的数据库功能告诉我列表中的哪些值不存在而不需要将这么大的列表返回到应用程序层。

来自David Faber的下面检查答案的

[解决方案],这是我从应用程序层角度(ruby on rails)的解决方案,以防任何人感兴趣。我编写了这个方法,因此它可以包含在你想要使用它的任何模型中,并接受列和值列表作为参数: [更新]参数化临时表名称并相应地设置数据类型

    def self.unfound_values_by_column values, column
      quoted_values = values.collect {|value| "('#{value}')"}.join(",")
      conn = self.connection # get this model's connection if different than base
      temp_table_name = "temp_values_for_unfound_lookup_table"
      datatype = self.columns_hash[column].sql_type
      begin
        conn.execute(
          "DROP TEMPORARY TABLE IF EXISTS #{temp_table_name}"
        )
        conn.execute(
          "CREATE TEMPORARY TABLE #{temp_table_name} (`#{column}` #{datatype})"
          )
        conn.execute(
          "INSERT INTO #{temp_table_name} (#{column}) VALUES #{quoted_values}"
        )
        unfound = conn.select_values(
          "SELECT temp.`#{column}` FROM `#{temp_table_name}` temp 
            WHERE NOT EXISTS ( 
              SELECT 1 FROM `#{self.table_name}` my
                WHERE my.`#{column}` = temp.`#{column}`
            )"
        )
      ensure
        conn.execute(
          "DROP TEMPORARY TABLE IF EXISTS #{temp_table_name}"
        )
      end
     unfound
    end

3 个答案:

答案 0 :(得分:1)

您最好的选择是创建一个临时表(仅对当前会话可见,并在该会话结束时删除),在all_values中插入所有值,然后将其与现有表进行比较。例如,

CREATE TEMPORARY TABLE `all_values`
(
    `myvalue` VARCHAR(30)
);

-- insert values

SELECT av.`myvalue`
  FROM `all_values` av
 WHERE NOT EXISTS ( SELECT 1 FROM `table1` t
                     WHERE t.`ColA` = av.`myvalue` );

我个人认为WHERE EXISTS语法比使用LEFT JOIN的{​​{1}}更容易,但是YMMV。

答案 1 :(得分:0)

您可以使用派生表:

SELECT * FROM (
  SELECT "a" AS colA
  UNION ALL SELECT "b"
  UNION ALL SELECT "c"
  UNION ALL SELECT "d"
) all_values
WHERE all_values.colA COLLATE utf8_general_ci NOT IN (SELECT colA FROM table1);

我使用COLLATE来避免table1与all_values中的值之间的整理冲突。

答案 2 :(得分:0)

我使用LEFT JOIN构建了一个小例子。表DATA保存您的测试数据和表DATA_LIST所有可能的数据。 SELECT给出不在表DATA中的所有列。

not_found_values:'C','c'

/* your values */
CREATE TABLE data (
  col VARCHAR(10) NOT NULL
);


INSERT INTO data1 VALUES
( 'A'), ('a'), ('B'), ('b' );

/* hole data list */
CREATE TABLE data_list (
  col VARCHAR(10) NOT NULL
);


INSERT INTO data_list VALUES
( 'A'), ('a'), ('B'), ('b' ), ('C'),('c');

/* show all values that not found */
SELECT dl.col AS not_found_values
FROM
  data_list dl
LEFT JOIN data d
ON d.col = dl.col
WHERE
  d.col IS NULL
 ORDER BY dl.col;