【问题标题】:SQL query Inner joins returns multiple rowsSQL查询内连接返回多行
【发布时间】:2015-01-30 20:02:28
【问题描述】:

我们有 2 张桌子;表 1,表 2。

table1

CNTY | ZIP  | SERVICE
111  | 1234 |  N
111  |      |  Y 
112  |      |  Y

table2

CNTY | ZIP  |
111  | 1234 |
111  | 4321 |
112  | 4433 |

我们正在使用 oracle 并尝试以下查询 -

SELECT t1.SERVICE
  FROM table1 t1
 WHERE t1.CNTY IN (SELECT t2.CNTY
                     FROM table2 t2
                    WHERE t2.ZIP = '4433')

返回 Y,这是预期的行为。但是如果我们发送t2.zip='4321',它会返回 2 行,但我们期望的是 1 行 (Y)。另外,如果我们发送t2.zip='1234' 应该返回'N'。但是,上面的查询返回 2 行。

我是数据库方面的新手。我们尝试过,但无法在一个单一的声明中得到它。有没有办法获得预期的行为?

基本上我对查询的期望是 -

  1. 它应该始终从table1 返回SERVICE 值。如果它在table1 中找到ZIP,它应该返回匹配zip 的SERVICE 值。
  2. 如果在table1 中没有匹配的ZIP,那么它应该在table2 中找到与给定zip 关联的CNTY,然后从table2 中获取CNTY 值,它应该找到SERVICE 中的 table1 值用于匹配 CNTY 并返回该值。

例如:对于 ZIP 4321,table1 中没有匹配的条目,但 table2 中的 4321 与 111 相关联,因此对于 table1 中的 111,SERVICE 值为 Y。因此,查询应返回 Y。

【问题讨论】:

    标签: java sql oracle hibernate oracle10g


    【解决方案1】:

    我不知道你为什么只期望一排。让我们检查一下查询的作用:

    SELECT t2.CNTY FROM table2 t2 WHERE t2.ZIP = '4321'
    

    这将返回一个值:111,对应于以下行:

         111  | 4321 |
    

    所以完整的查询等价于

    SELECT t1.SERVICE FROM table1 t1 WHERE t1.CNTY IN (111)
    

    这会返回这两行的服务,因为它们的 CNTY 都等于 111:

         111  | 1234 |  N
         111  |      |  Y 
    

    【讨论】:

      【解决方案2】:

      它返回两个,因为您在 table1 中有两行,城市为 111

      select t1.* from
      table1 t1
      join table2 t2 on t2.city = t1.city and (t2.zip = t1.zip or t2.zip is null)
      

      现在您正在加入城市和邮政编码,或者如果没有邮政编码。

      这将只返回一行,但如果有两个城市行 111 并且没有邮政编码,那么它将返回 2

      (注意:未测试此 SQL - 我是从内存中完成的;))

      【讨论】:

        【解决方案3】:

        有什么方法可以得到预期的行为?

        是的,您可以加入CNTYZIP 上的表格。

        SELECT t1.SERVICE
          FROM table1 t1, table2 t2
         WHERE t1.CNTY = t2.CNTY AND t1.ZIP = t2.ZIP
           AND t2.ZIP = '1234'
        

        但是,上述内容仍然不适用于 ZIP '4321'。为此,连接必须更复杂。

        SELECT COALESCE(t1a.SERVICE, t1b.SERVICE) AS SERVICE
          FROM table2 t2
            LEFT JOIN table1 t1a ON t1a.CNTY = t2.CNTY AND t1a.ZIP = t2.ZIP
            LEFT JOIN table1 t1b ON t1b.CNTY = t2.CNTY AND COALESCE(t1b.ZIP, '') = ''
          WHERE t2.ZIP = '4321'
        

        第二个查询适用于所有情况。

        【讨论】:

        • 上述查询将不起作用,因为 `t1.ZIP = t2.ZIP` 将失败,因为 t1.zip 为空且 t2.zip 为 4321 对吗?
        • 我现在明白了,谢谢你的澄清。请参阅我的新答案。
        • 感谢您的宝贵时间。但是,由于某种原因,即使是新查询也不会返回 4321 的“Y”。相反,它会返回空/null。(我在这里期待的是,- 1。它应该始终从 table1 返回值。如果找到zip in table1 它应该返回匹配 zip 的服务值。 2. 如果 table1 中没有匹配的 zip,那么它应该在 table2 中找到与给定 zip 关联的 CNTY,然后从 table2 中获取 CNTY 值,它应该找到为匹配的 CNTY 提供 table1 中的服务值并返回该值。
        【解决方案4】:
        select service from (
          select row_number() over (order by t1.zip nulls last) rn, service 
            from table1 t1 
              join table2 t2 on t2.cnty = t1.cnty and (t2.zip = t1.zip or t1.zip is null) 
            where coalesce(t1.zip, t2.zip) = '1234')
          where rn=1
        

        row_number 用于对来自join 的两行记录进行排序,例如 zip=1234。 每个 zip 的查询都能正常工作。

        你也可以使用:

          select 
              case 
                when exists (select 1 from table1 where zip='1234') 
                then 
                  (select service from table1 where zip='1234')
                else
                  (select service from table1 where zip is null 
                      and cnty = (select cnty from table2 where zip='1234')) 
            end service
            from dual
        

        喜欢这里:

          with zips as (select '1234' zip from dual 
            union select '4321' from dual 
            union select '4433' from dual 
            union select 'TEST' from dual)
          select zips.zip, 
              case 
                when exists (select 1 from table1 where zip=zips.zip) 
                then 
                  (select service from table1 where zip=zips.zip)
                else
                  (select service from table1 where zip is null and cnty = 
                     (select cnty from table2 where zip=zips.zip)) 
              end service
            from zips
        
        zip     service
        1234    N
        4321    Y
        4433    Y
        TEST    null    
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-02
          • 1970-01-01
          • 2012-07-17
          • 1970-01-01
          • 1970-01-01
          • 2011-01-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多