【问题标题】:Select elements that are absent in a table from a list of value从值列表中选择表中不存在的元素
【发布时间】:2015-04-23 15:58:46
【问题描述】:

我有一个带有 id 和标签的表 T

ID  LABEL
1   label_1
2   label_2
3   label_3

我有一个标签列表:

('label_1', 'label_4', 'label_6' )

我想选择表 T 中不存在的那些。在我的情况下,我会得到“label_4”和“label_6”。 如何在 SQL 中做到这一点?


编辑 1

这些标签是外部值。我想在日志文件中打印我的表中不存在的值,可能使用假脱机


编辑 2

我目前正在尝试使用 pl/SQL 将我的所有值放入一个表中,因为它基本上是一个巨大的值列表。我有这个:

DECLARE
  type array_t is varray(603) of varchar2(50 BYTE);
  labels array_t := array_t(
        '210',
                'label_1',
                'label_6',
                'label_4'
  );
BEGIN
  For i in labels LOOP

    Insert Into TEMP_LABEL (LABEL)
    Values (i);

  END LOOP;
  commit;
END;

但我收到以下错误:pls-00456 item is not a cursor 我被困在这里了。

【问题讨论】:

  • label_4label_6 是否存在于某个查找表中?或者它们是可能根本不在数据库中的外部值?您究竟希望您的结果是什么样的?
  • 那些标签是外部值。我想在日志文件中打印我的表中不存在的值,可能使用spool
  • 答案取决于您没有指定的数据库引擎。
  • 你能用这些外部值创建一个临时表或表变量吗?你用的是什么数据库系统?创建临时表后,您应该能够执行 LEFT JOIN 然后过滤 NULL 值以获得所需的内容。
  • 这是否意味着如果不将我的外部值存储在(临时)表中,我要求做的事情是不可能的?

标签: sql select plsql


【解决方案1】:

请参阅我的sqlfiddle(和postgres version)以获取使用表格的解决方案

相关查询如下:

   SELECT T_TEMP.LABEL, T.LABEL
     FROM T_TEMP
LEFT JOIN T
       ON T_TEMP.LABEL = T.LABEL
    WHERE T.LABEL IS NULL;

如果有充分的理由不使用表来存储这些值,请告诉我们。

根据数据集的大小,在以下查询之间进行选择可能会对性能产生影响(请参阅excellent explanation comparing the methods):

-- LEFT JOIN / IS NULL
SELECT    T_TEMP.LABEL, T.LABEL
FROM      T_TEMP
LEFT JOIN T ON T_TEMP.LABEL = T.LABEL
WHERE     T.LABEL IS NULL;

-- NOT EXISTS
SELECT  T_TEMP.LABEL
FROM    T_TEMP
WHERE   NOT EXISTS
    (
    SELECT  T.LABEL
    FROM    T
    WHERE   T_TEMP.LABEL = T.LABEL
    );

-- NOT IN    
SELECT  T_TEMP.LABEL
FROM    T_TEMP
WHERE   LABEL NOT IN
    (
    SELECT  T.LABEL
    FROM    T
    );

随着数据集的增长,LEFT JOIN / IS NULL 或 NOT EXISTS 应该执行得更好,但根据this fiddle 中的执行计划,NOT IN 似乎以最低的成本执行。

【讨论】:

  • 谢谢LEFT JOIN / IS NULL 方法似乎有效。奇怪的是,NOT IN 方法不会输出任何结果,即使它应该返回与其他方法相同的结果。我会尝试找出我的(很可能)错误来自哪里。
  • 如果您有其中一个在工作,我会坚持这样做,但如果您确实希望 NOT IN 工作,请仔细检查您是否拥有 WHERE LABEL NOT IN 而不是 WHERE NOT IN - 它不同于WHERE NOT EXISTS
【解决方案2】:

这是我在“编辑 2”中提供更多信息之前的回答。我认为需要更多特定于上下文的信息。无论如何,此代码返回不在原始表中的标签行:

CREATE TABLE OriginalTable (Id INT, Label VARCHAR(20));

INSERT INTO OriginalTable (Id, Label)
VALUES (1, 'label_1'), (2, 'label_2'), (3, 'label_3');

-- Create a table with the labels you want to compare
CREATE TABLE ComparisonTable (Id INT, Label VARCHAR(20));

INSERT INTO ComparisonTable (Id, Label)
VALUES (1, 'label_1'), (2, 'label_4'), (3, 'label_6');

SELECT Label
FROM ComparisonTable
WHERE Label NOT IN (SELECT Label FROM OriginalTable);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 2017-04-19
    • 2019-08-14
    相关资源
    最近更新 更多