【问题标题】:Use SQL subquery to count number of rows in table and pass/fail java test based on the result使用 SQL 子查询计算表中的行数并根据结果通过/失败 java 测试
【发布时间】:2018-10-20 14:22:39
【问题描述】:

下面是我的 2 个 SQL Server 表。

地址

addressId | addressName |
2         | testAddress |

友情链接

linkId | clientId | addressId |
1      | 4        | 2         |

我正在尝试编写一个使用 SQL 子查询来检查 taddress 中是否存在记录的 java 测试。

例如:

SELECT COUNT(*) FROM Taddress
WHERE addressId =
(SELECT addressId FROM Tlink
WHERE clientId = param)

目前,当我运行以下测试时,即使 tLink 中不存在 clientId 参数,测试也始终通过。

try {
        dbAccessSetUp();
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM taddress a INNER JOIN tlink l on a.address_id = l.internal_address_id WHERE l.ext_client_id =" + this.clientNo);

        if(!rs.next()) {
            fail("Record does not exist in taddress based on ExtClientNo");
        }

        int count = 0;

        while(rs.next()) {              

            count = rs.getInt(1);
            System.out.println("number of count : " + count);
            assertTrue(0 < count);
        } 
        rs.close(); 
    } catch(SQLException se) { 
        se.printStackTrace(); 
        assertEquals(true, false);
    } catch(Exception e) { 
        e.printStackTrace();
        assertEquals(true, false);
    } finally { 
        try { 
            if(stmt!=null) stmt.close();  
        } catch(SQLException se2) {
            assertEquals(true, false);
        } 
        try { 
            if(conn!=null) conn.close(); 
        } catch(SQLException se) {
            se.printStackTrace(); 
            assertEquals(true, false);
        } 
    } 

【问题讨论】:

  • 你是否传递了一个特定的值来代替参数?
  • @Mohan 嗨,是的,这将是从黄瓜功能文件传入的值。因此,如果一个有效值(与 tLink 中的 clientId 匹配的值)作为参数传入,那么我想使用该行的 addressId 来计算 Taddress 中的行数。另外,如果一个无效值(与 tLink 中的 clientId 不匹配的值),那么我希望测试失败
  • 基本上,如果 tLink 中没有该 clientId 的记录,我希望测试失败,如果 tAddress 中也没有匹配记录,我希望测试失败
  • 您是否进行了任何调试以查看 rs.getInt(1) 为您的测试用例返回的内容?
  • 我很惊讶测试总是通过。您可能需要像 MatBailie 指出的那样打印 count 的值,看看它是否返回大于零的无效值

标签: java sql sql-server subquery


【解决方案1】:

根据您上面的代码示例,这应该适合您:

try {
        dbAccessSetUp();
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*)FROM taddress A INNER JOIN tlink L ON A.address_id = L.internal_address_id WHERE L.ext_client_id =" + this.clientNo);
        int count=0;
        while(rs.next()) {
            count =  ((Number) rs.getObject(1)).intValue();

        }

        if(count > 0) {
            assertTrue(true);
            System.out.println(count + " record(s) in taddress based on ExtClientNo");
        }
        else {
            fail("No records in taddress");
        }

    }catch(Exception ex) {
        System.out.println(ex.getMessage());
    }

如果出现以下情况,这将失败:

  • tlink 中没有您的客户的匹配记录否
  • tlink中有匹配记录,但taddress中没有匹配记录

这将通过,如果:

  • tlink 中有匹配记录,taddress 中有匹配记录

【讨论】:

    【解决方案2】:

    对于您的查询,直到您在Tlink 表中有超过 1 行之前,它都会运行而不会出错,因此最好将其更改为简单的连接作为

    SELECT COUNT(*)
    FROM Taddress A INNER JOIN Tlink L ON A.addressId = L.addressId
    WHERE L.clientId = Param;
    

    现在,我们同意该查询将返回正确的结果,但您的 Java 代码没有像您提到的那样工作

    目前,当我使用上述查询运行测试时,即使 tLink 中不存在 clientId 参数,测试也始终通过。

    上面的查询只会返回一行(一个值),所以不需要循环,这段代码没用

    while(rs.next()){
        count = rs.getInt(1);
        assertTrue(0 < count);
    }
    

    您需要的只是获取查询返回的值并检查它是否大于0,类似于

    count =  ((Number) rs.getObject(1)).intValue();
    int cmp;
    if (count > 0)
    // Exists;
    else 
    //Not exists;
    

    或者

    assertTrue(count.equals(0));
    

    【讨论】:

    • 是的,第一次没看懂问题。
    • 这确实是一个更好的 SQL 语句。 不会,但是,与 OP 编写结果相比,结果会发生变化,那么 Java 中的行为会发生什么变化
    • @MatBailie 你的意思是 OP 想要一个 Java 代码的答案吗?
    • @Sami - 阅读问题!他们希望在 Java 中进行测试以查看是否存在某些记录。您的 SQL 将返回完全与其 SQL 相同的结果。因此,这实现了 nothing。这是更好的 SQL,但对 OP 正在寻找的行为产生了 zero 差异。
    • @Sami 感谢您的回答,您能否提供适用于您的加入的 java 测试方法?
    【解决方案3】:

    进行查询:

    SELECT COUNT(*) 
    FROM taddress a INNER JOIN tlink l on a.addressid = l.addressID
    WHERE l.clientid = @param
    

    如果出现以下任一情况,这将返回 0:

    • 该参数没有 tlink
    • 没有该 tlink 的 taddress

    如果你想知道关系破裂的地方:

    SELECT COUNT(*) as count_link, COUNT(a.addressid) as count_address 
    FROM taddress a RIGHT JOIN tlink l on a.addressid = l.addressID
    WHERE l.clientid = @param
    

    关于您断言计数始终> 0,无论您传递什么@param,我希望看到一些额外的调试/屏幕截图/打印输出等表明

    编辑

    所以你的代码的问题是:

    你运行 sql 然后调用if(!rs.hasNext())

    您的结果集确实有一行,因此对 rs.next 的调用返回 true,您对此取反,因此 if 测试返回 false,if 不运行,并且您的结果集现在指向来自询问。 唯一一行数据 - 您现在应该读取数据,但您不...

    接下来你说while(rs.hasNext()) 这会将你的结果集推进另一行,因此它不再指向计数数据。没有更多的数据行,所以这个调用返回 false 并且 你的 while 循环体永远不会运行 - 你永远不会从结果集中拉出任何数据,你的断言永远不会运行等等

    重新编写代码,以便在第一个 if 中执行 assert() 并放弃 while 循环

    if(rs.next())
      assert(rs.getInt(1) > 0);
    

    这种形式的计数查询总是返回一行,测试结果集没有数据是没有意义的。如果查询运行失败,则会生成异常

    【讨论】:

    • 这确实是一个更好的 SQL 语句。 不会,但是,与 OP 编写结果相比,它会改变结果,因此不会改变 Java 中的行为
    • 感谢您的回答。如果我将它插入到上面的方法中,这个查询会起作用吗,或者我需要对方法进行更改? IE。抛出 try/catch 等?
    • 1.如果使用查询的 taddress 中存在记录,则测试应该通过。 2. 如果 tLink 中不存在该参数的记录,则测试应该失败。 3. 如果从 tLink 检索到的 addressId 在 taddress 中没有记录,则测试应该失败
    • 如果您使用第二种形式,您可能需要添加rs.getInt(2) 来检索地址记录的数量,并编写一些额外的逻辑来测试该结果。..
    • assertTrue(rs.getInt(1) &gt; 0 &amp;&amp; rs.getInt(2) &gt; 0) 如果使用第二种形式。 assertTrue(rs.getInt(1) &gt; 0) 第一种形式就可以了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 2018-09-30
    • 1970-01-01
    相关资源
    最近更新 更多