如何在SQL查询中传递List

19

我有一个值列表(例如1, 2, 3),我想将该列表传递到SQL查询中:

"select name from tbl where id in" + list 

我该如何实现这个?


你使用什么来构建你的SQL? - hvgotcodes
11个回答

12

你需要直接将列表放入 SQL 语句中。

示例:

String sql="select name from tbl where id in ("+StringUtils.join(list, ',')+")";
Statement st=connection.createStatement();
st.execute(sql);

使用Java 8,您可以使用String.join(",", list),但是对于字符串参数,此解决方案不适用。 - Pino
2
这段代码存在安全问题。由于值未经转义,可能会发生SQL注入。 - Iouri Goussev

10

我看到你在回复评论时使用了HQL。如果是这样的话,Hibernate的开发人员为您提供了方便的方法,在查询中只需指定:

where id in (:ids)

然后使用setParameterList("ids", list),并传递您的列表。Hibernate将为您完成所有的展开操作!


2
SQL语法如下:
select name from tbl where id in (1,2,3)

你需要做的就是构建逗号分隔的项目列表并将其插入字符串中。

哦,还有必要的 SQL 字符串构建警告:不要这样做!


1

这取决于你如何构建你的SQL。如果你自己构建它(不好的想法),你需要让SQL看起来像这样 -

... where id in (1,2,3)...

由于在你的评论中你指定了Hibernate HQL,类似于 -

Query query = session.createSQLQuery("from User where id in :ids ");
query.setParameter("ids", idsList);
List list = query.list();

这应该能让你开始了解。请注意,User是您映射到要查询的表的对象的名称。


@vinay,请通过编辑问题将失败的代码和堆栈跟踪发布在问题中。 - hvgotcodes

0
将列表作为逗号分隔的列表传入,并使用拆分函数将其拆分成临时表变量。
CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(512))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT pn,
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
  )

3
谈论使用战术核武器猎杀兔子...或使用微软的报告服务器,基本上是相同的事情。 - Blindy
我想我误解了问题,认为它是“如何将这个列表传递到存储过程中”。我的错。 - user891973

0

我知道这已经过去很长时间了,但当我寻找解决方案时,这就是返回的页面,正好解决了这个问题。似乎所有答案都不完美,因为有各种原因(包括 SQL 注入的可能性,这是一个真正的问题)。所以,这是我的解决方案:

/**
 * Checks if this range exists in the database already.
 * If it does, it will return the original name.
 * @param products the list of product names to check
 * @return  The range's name in the database
 * @throws SQLException if SQL fails
 *   (or if it exists but with multiple names)
 */
private String getOriginalName(final List<String> products)throws SQLException {
  if (products.isEmpty()) {
    throw new SQLException("Cannot check an empty list");
  }
  try (Connection connection = ConnectionPoolConfigRulesUtils.getConnection();
      PreparedStatement statement = connection.prepareCall(
          "SELECT [rangeName] FROM [dbo].[products] WHERE [productName] IN ("
          + repeatString("?", ", ", products.size()) + ") GROUP BY [rangeName]")) {
    int fieldNo = 1;  //NOPMD DU anomaly
    for (final DbProduct product: products) {
      statement.setInt(fieldNo++, product.getId());
    }
    try (ResultSet rset = statement.executeQuery()) {
      final String rangeName;
      if (rset.next()) {
        //Get the first range name
        rangeName = Nz.nz(rset.getString("rangeName"));
      } else {
        //There isn't one so return empty string
        rangeName = "";
      }
      if (rset.next()) {
        //But, if there are multiple ranges, this is an error so treat it as such
        throw new SQLException("The products you are trying to save exist already in the dabase under more than one range. "
            + "Cannot process the change");
      }
      return rangeName;
    }
  }
}

0

您可以编写类似的代码,然后将uuidsWithRequiredPattern传递给SQL。 在下面的示例中,我需要具有以单引号为前缀、以单引号为后缀并用逗号分隔的uuids。

List<UUID> uuidList = Arrays.asList("581394be-6a27-11ea-bc55-0242ac130003","681394be-6a27-11ea-bc55-0242ac130003")
String uuidsWithRequiredPattern = uuidList.stream()
                .map(UUID::toString)
                .collect(Collectors.joining(",", "'", "'"));

0

-1

字符串 sqlQuery = "select name from tbl where id in" + sqlFormatedList(list);

private String sqlFormatedList(List<Integer> list){
 StringBuilder sb = new StringBuilder();
 sb.append("(");
 for (Integer i : list){
   sb.append(i+",");
 }
 sb.deleteCharAt(sb.length() -1);
 sb.append(")");
 return sb.toString();
}

现在我得到的是 [1,2,3],但我想要一个逗号分隔的字符串。我正在与ID进行比较,而ID是整数,而“sb”是字符串,所以该如何处理呢? - n92
抱歉,我会在1分钟内为您修复它,已经修好了。 - undefined

-1
private static String sqlFormatedList(List<String> list){
     StringBuilder sb = new StringBuilder();
     sb.append("('");
     for (String i : list){
       sb.append(i+"','");
     }
     sb.deleteCharAt(sb.length() -1);
     sb.deleteCharAt(sb.lastIndexOf(","));
     sb.append(")");
     return sb.toString();
    }

完全容易受到SQL注入攻击,并且不考虑带有单引号的字符串。 - TT.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接