【问题标题】:Oracle SQL where to filter multiple rowsOracle SQL 在哪里过滤多行
【发布时间】:2018-06-13 17:38:24
【问题描述】:

我确信有一个简单的解决方案可以解决我正在尝试做的事情,但我就是想不通。

表 A - 列 - ITEMNUM - ITEMNAME

                   1      Test1
                   2      Test2
                   3      Test3
                   4      Test4
                   5      Test5
                   6      Test6 

表 B - 列 - ITEMNUM CHAR

                   1      A
                   1      B
                   2      A
                   2      C
                   3      A
                   3      D
                   4      A
                   4      E
                   5      A
                   5      F
                   6      A
                   6      F

我想做的是

select itemname 
from A, b
where a.itemnum = b.itemnum

然后我只想要 char = 'A' 的行,但当 B、C 或 D 也具有相同的 itemnum 时不想要。 itemnum 必须有一个字符为“A”,然后它可能是具有相同 itemnum 的其他字符,但不能是 B、C 或 D。并非所有 itemnum 的字符都为“A”。希望这是有道理的。

Test4、Test5 和 Test6 应该是唯一返回的。

我必须将此代码放入另一个不允许我使用 pl/sql 的程序中。

建议?

【问题讨论】:

  • 有什么限制吗?对于特定的 ITEMNUM,“A”字符值能否在表 B 中多次出现?
  • 在表 B 中,char 'A' 每个 itemnum 只会出现一次。
  • 从您的 cmets 的答案来看,我不确定结果应该是什么。您能否展示一下您的案例的结果行是什么样的?

标签: sql oracle


【解决方案1】:

您可以使用listagg 构建一个包含每个项目名称的所有字符的字符串。然后您可以过滤带有A 但没有BCD 的行:

with    list as
        (
        select  ITEMNAME
        ,       listagg("CHAR") within group (order by "CHAR") chars
        from    TableA a
        join    TableB b
        on      a.ITEMNUM = b.ITEMNUM
        group by
                ITEMNAME
        )
select  *
from    list
where   chars like '%A%'
        and not regexp_like(chars, '[BCD]')

Example at SQL Fiddle.

【讨论】:

    【解决方案2】:

    在 B 上使用不存在的自联接

    select itemname 
    from A, b
    where a.itemnum = b.itemnum
    and not exists( select 1 from b2 where b2.itemnum = b.itemnum and b2.char in ('B', 'C', 'D'));
    

    您可能也想开始使用 ANSI 连接语法:

    select itemname 
    from A
    join b on a.itemnum = b.itemnum
    where not exists( select 1 from b2 where b2.itemnum = b.itemnum and b2.char in ('B', 'C', 'D'));
    

    【讨论】:

    • 对不起,我的问题可能不清楚,但我认为你很接近。我需要选择 a.itemname、b.char 并取回 test4 A test4 E test5 A test5 F test6 A test6 F。这样我只会得到 char = A 作为回报
    • 然后从子句中删除 b.char = 'A'。我会更新我的答案
    【解决方案3】:

    这样的东西应该可以工作

    SELECT a.itemname
    FROM a
    WHERE EXISTS (
      SELECT 1
      FROM b
      WHERE b.itemnum = a.itemnum
      AND b.char = 'A'
    )
    AND NOT EXISTS (
      SELECT 1
      FROM b
      WHERE b.itemnum = a.itemnum
      AND b.char IN ('B', 'C', 'D')
    )
    

    编辑:不确定这是否是您想要的(请分享预期的结果结构和数据,例如您对表 A 和 B 所做的),但这可能是第二次:

    SELECT a.itemname, b.char
    FROM a
    INNER JOIN b
    ON b.itemnum = a.itemnum
    WHERE EXISTS (
      SELECT 1
      FROM b b_char
      WHERE b_char.itemnum = a.itemnum
      AND b_char.char = 'A'
    )
    AND NOT EXISTS (
      SELECT 1
      FROM b b_char
      WHERE b_char.itemnum = a.itemnum
      AND b_char.char IN ('B', 'C', 'D')
    )
    

    编辑 2:看看这个SQL Fiddle,看看它是如何工作的。

    结果基本上是:

    项目名称 |字符 ---------+----- 测试4 |一种 测试4 |乙 测试5 |一种 测试5 | F 测试6 |一种 测试6 | F

    【讨论】:

    • 对不起,我的问题可能不太清楚,但我认为你很接近。我需要选择 a.itemname, b.char 并取回 test4 A test4 E test5 A test5 F test6 A test6 F
    【解决方案4】:

    我的两分钱

    select itemnum from (
       select a.itemnum, 
           max(case when b.char in ('B','C','D') then 'Y' else 'N' end) bad_check,
           max(case when b.char = 'A' then 'Y' else 'N' end) has_an_a
       from A, b
       where a.itemnum = b.itemnum
       group by a.itemnum
    ) where has_an_a='Y'
    and bad_check='N';
    

    【讨论】:

      猜你喜欢
      • 2017-03-31
      • 1970-01-01
      • 2021-11-25
      • 2012-09-13
      • 2016-07-30
      • 1970-01-01
      • 2021-01-29
      • 2011-12-18
      • 2018-12-03
      相关资源
      最近更新 更多