【问题标题】:sql - single query to return values that are not presentsql - 单个查询返回不存在的值
【发布时间】:2011-12-21 21:51:35
【问题描述】:

例如,您有一个只有一列的简单表格。 即。

CREATE TABLE movies   (title VARCHAR2(255 BYTE))

使用以下数据进行设置:

INSERT INTO movies   (title) VALUES ('Scream');
INSERT INTO movies   (title) VALUES ('Blair Witch');
INSERT INTO movies   (title) VALUES ('Friday the 13th');
INSERT INTO movies   (title) VALUES ('Scary Movie');
INSERT INTO movies   (title) VALUES ('Hide and Seek');
INSERT INTO movies   (title) VALUES ('Alien vs Predator');

是否有单个查询或 PL/SQL 将动态执行以下操作(即,无需为每个值手动执行“UNION select 'scream' from dual...”)?

显然这个查询是错误的,但你明白了:

Select * from movies
where title in (
'Scream',
'Scary Movie',
'Exorcist',
'Dracula',
'Saw',
'Hide and Seek'
)

期望的结果是“WHERE TITLE IN”子句中的每个值的记录,其中该记录不存在于表中。 即。

'Exorcist'
'Dracula'
'Saw'

【问题讨论】:

  • 所有选择的行都来自关系(表)。您必须在某个时刻创建一个表,可能像您所说的那样为每个值使用“UNION select 'scream' from dual...”。

标签: sql database oracle plsql


【解决方案1】:

您可以使用表类型和函数 table() 将列表转换为表。

CREATE OR REPLACE TYPE varchar_list_type as table of varchar2(100);

CREATE OR REPLACE function in_varchar_list ( p_string in varchar2 ) return varchar_list_type
as
    l_data             varchar_list_type := varchar_list_type();
    l_string           long default p_string || ',';
    l_n                number;
begin

    loop
        exit when l_string is null;

        l_data.extend;
        l_n := instr( l_string, ',' );
        l_data( l_data.count ) := substr( l_string, 1, l_n-1 );
        l_string := substr( l_string, l_n+1 );

    end loop;
    return l_data;
end;

然后像这样使用:

select * from TABLE(select cast(in_varchar_list('foo,bar,baz') as varchar_list_type) from dual)

当然,您可以使用绑定变量或普通变量来代替硬编码字符串 'foo,bar,baz'。

编辑:查询中的错字^_^"

【讨论】:

    【解决方案2】:

    如果您使用的是 10g 或更高版本,您可以构建一个将 CSV 字符串转换为动态表的函数。查看this other response 中的字符串标记器代码。

    你会这样使用它:

    select * from movies
    where title NOT in (
             select * 
              from table (string_tokenizer
                          (
                              'Scream, Scary Movie,Exorcist,Dracula,Saw,Hide and Seek'
                            )
    
                      )
         )
    /
    

    这是一个稍微简单的实现,不需要任何额外的基础设施:

    SQL> select * from table(sys.dbms_debug_vc2coll('Scream',
    'Scary Movie',
    'Exorcist',
    'Dracula',
    'Saw',
    'Hide and Seek'
     ))
    /
      2    3    4    5    6    7    8  
    COLUMN_VALUE
    --------------------------------------------------------------------------------
    Scream
    Scary Movie
    Exorcist
    Dracula
    Saw
    Hide and Seek
    
    6 rows selected.
    
    SQL> 
    

    这类似于the Table Value Constructor,但它只适用于单列“表格”。

    【讨论】:

    • 关键字table 和名称sys.dbms_debug_vc2coll 是我要找的。帮助我避免多次重复union select。谢谢!
    【解决方案3】:

    您想要的是“表值构造函数” 功能。我不认为甲骨文支持这一点。

    请参阅 Joe Celko 的文章:Table Value Constructors in SQL Server 2008 以及从那里获取的示例:

    SELECT *
    FROM
      ( VALUES
          (101, 'Bikes'),
          (102, 'Accessories'),
          (103, 'Clothes')
      ) AS Category(CategoryID, CategoryName);
    

    【讨论】:

    • 耻辱oracle没有这个
    • 我认为 DB2 也有。并且 SQL-Server 仅限于最新 (2008) 版本。
    • 我要补充一点,有些版本的 DB2 有这个。我大量使用 v7r4 及更高版本,它确实支持它。一些较旧的机器(v5),虽然......不是那么多。
    • @Meower68 不确定该信息是否应该进行编辑。出于好奇,DB2(您使用的版本)是否支持此(不带 SELECT 的查询):VALUES (101, 'Bikes'), (102, 'Accessories'), (103, 'Clothes') ;(Postgres 支持)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    相关资源
    最近更新 更多