【问题标题】:SQL - How can I return the IDs from a where clause list that are not in the table?SQL - 如何从 where 子句列表中返回不在表中的 ID?
【发布时间】:2011-02-04 21:36:31
【问题描述】:

给定这样的查询:

select customerId
  from customer
 where customerId in (
          1, 2, 3
       )

where 子句的列表中有数百个 ID;如何从 where 子句中的列表中返回不在表中的 ID?

这是一个生产表,我只能对其运行 select 查询。我只能运行select 查询;我没有创建任何表的权限。

【问题讨论】:

  • 为什么您的应用程序中有数百个在数据库中不存在的 CustomerID?
  • @Ronnis - 我正在回答系统所有者的临时报告请求。
  • @abboq - 已更新答案以解决仅 SELECT 访问的问题
  • 非常感谢大家的洞察力。
  • @abboq,我想说的是:尽管 CustomerID 是“只是数字”,但它们在代表实际客户的意义上是特殊的。所以你一定是从某个地方得到了客户的号码。我敢打赌,您拥有的 customerID 列表是另一个 SQL 查询的结果。我还认为您想要实现的目标可以通过原始客户表和您获得所有 ID 的查询来完成。

标签: sql db2


【解决方案1】:

您可以使用 VALUES 语句在 SELECT 中伪造一个表:

SELECT t1.customerId
FROM
  (VALUES (1), (2), (3), (4)) AS t1(customerId)
LEFT OUTER JOIN
  customer c
ON
  c.customerId = t1.customerId
AND
  c.customerId IS NULL

参考文献

【讨论】:

    【解决方案2】:

    在 DB2 上有一种更简单的方法来执行此操作,即使用 VALUES 动态构建表:

    select 
       customerID
    from 
       table(values (1),(2),(3)) as a (customerID)  
    except 
    select 
       customerID 
    from 
       customers;
    

    请注意,您需要在每个值周围加上括号,以确保每个值都是表结构中的“行”。

    对于此示例,如果您的 customers 表的 customerID 为 1、2、3 和 4,则此查询将返回值 4。

    这应该适用于 DB2 UDB for z/OS 版本 8 和更高版本。它也可以在 DB2 for Linux/UNIX/Windows 上工作。

    【讨论】:

      【解决方案3】:

      我会将这些 ID 放入一个表结构中,然后将其与您的客户表连接起来。

      select t.customerId
          from SomeTable t
              left join customer c
                  on t.customerId = c.customerId
          where c.customerId is null
      

      【讨论】:

      • OP 只能运行 SELECT 查询
      【解决方案4】:

      真正残酷的方法,对于大多数 DBMS,这将起作用(Oracle 除外,您需要 select..from dual)。即使您无权创建/更新表并且只能SELECT

      ,这也应该适用于 DB2
      select N1.N * 1000 + N2.N * 100 + N3.N * 10 + N4.N as NonExistentCustomerID
      from (
          select 1 as N union all select 2 union all select 3 union all
          select 4 union all select 5 union all select 6 union all
          select 7 union all select 8 union all select 9 union all
          select 0) N1
      cross join (
          select 1 as N union all select 2 union all select 3 union all
          select 4 union all select 5 union all select 6 union all
          select 7 union all select 8 union all select 9 union all
          select 0) N2
      cross join (
          select 1 as N union all select 2 union all select 3 union all
          select 4 union all select 5 union all select 6 union all
          select 7 union all select 8 union all select 9 union all
          select 0) N3
      cross join (
          select 1 as N union all select 2 union all select 3 union all
          select 4 union all select 5 union all select 6 union all
          select 7 union all select 8 union all select 9 union all
          select 0) N4
      where N1.N * 1000 + N2.N * 100 + N3.N * 10 + N4.N in (1,2,3)
          and not exists (
              select * from customer c where c.customerid = v.number + v2.number*1000)
      

      根据需要扩展子查询以覆盖整个数字范围。

      如果您可以创建表格(或有一个方便的),请创建一个“数字”表格,而不是使用数字 0 到 9(10 条记录),并继续加入自身,即

      create table Numbers (N int)
      insert into Numbers
      select 1 union all select 2 union all select 3 union all
      select 4 union all select 5 union all select 6 union all
      select 7 union all select 8 union all select 9 union all
      select 0
      
      select N1.N * 1000 + N2.N * 100 + N3.N * 10 + N4.N as NonExistentCustomerID
      from numbers N1
      cross join numbers N2
      cross join numbers N3
      cross join numbers N4
      where N1.N * 1000 + N2.N * 100 + N3.N * 10 + N4.N in (1,2,3)
          and not exists (
              select * from customer c where c.customerid = v.number + v2.number*1000)
      

      numbers 表对于各种查询总是有用的。

      供 SQL Server 参考,假设数字在 0-2047 范围内,您可以使用

      select v.number
      from master..spt_values v
      left join customer c on c.customerid = v.number
      where v.type='P' and v.number in (1,2,3)
        and v.customerid is null
      

      如果您需要更大的范围,请继续加入 master..spt_values 以获得更大的范围

      select v.number + v2.number*1000 as NonExistentCustomerID
      from master..spt_values v
      inner join master..spt_values v2 on v2.type='P'
      where v.type='P' and v.number + v2.number*1000 in (1,2,3)
        and v.number between 0 and 999
        and not exists (
          select * from customer c where c.customerid = v.number + v2.number*1000)
      order by 1
      

      【讨论】:

      • 可能想要将 DB2 的东西向上移动,以便更明显。
      • 这个解决方案太疯狂了。请参阅下面的使用 VALUES 的解决方案。
      【解决方案5】:
      select customerId
        from customer
      EXCEPT
      select customerId
        from customer
       where customerId in (
                1, 2, 3
             )
      

      【讨论】:

        【解决方案6】:

        一种简单的方法是使用一个计数表,假设它被称为带有列号的数字 - 在所有数字中(此代码可能不是最好的,但应该清楚其意图是什么):

        select number
        from numbers
        where number in (1, 2, 3)
        and number NOT IN (select customerId from customer)
        

        另一种可能性是将您要查找的 id 写入实际的表或表变量中。

        【讨论】:

          猜你喜欢
          • 2022-01-17
          • 2019-04-05
          • 2022-01-02
          • 2014-02-09
          • 1970-01-01
          • 2022-01-13
          • 1970-01-01
          • 1970-01-01
          • 2014-05-03
          相关资源
          最近更新 更多