【问题标题】:Parameters in odd locations in Prepared Statements in Microsoft SQL and JDBCMicrosoft SQL 和 JDBC 中的 Prepared Statements 中奇数位置的参数
【发布时间】:2011-12-30 20:31:10
【问题描述】:

所以我在 Microsoft SQL 2008 中执行了以下语句:

  SELECT
  'UTC' AS timezone,
  rel.unique_id AS relay,sns.unique_id AS sensor,
  dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) AS time,
  SUM(CONVERT(FLOAT,dat.data)) AS total
  FROM sensor_data dat
   LEFT OUTER JOIN data_package pak ON dat.package_id = pak.id
   LEFT OUTER JOIN relays rel ON pak.relay_id = rel.id
   LEFT OUTER JOIN sensors sns ON dat.sensor_id = sns.id
   LEFT OUTER JOIN sensor_types typ ON sns.sensor_type = typ.id
   WHERE typ.name = 'Volume' AND dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) > ? AND dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) < ?
   GROUP BY rel.unique_id,sns.unique_id, dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0)
   ORDER BY time,relay,sensor

如果我像这样使用 jTDS/JDBC 驱动程序设置参数:

Parameter 1: 15
Parameter 2: 15
Parameter 3: 15
Parameter 4: 15
Parameter 5: 2011-10-31 20:00:00
Parameter 6: 15
Parameter 7: 15
Parameter 8: 2011-12-29 19:00:00
Parameter 9: 15
Parameter 10: 15

我得到错误:

Caused by: java.sql.SQLException: Column 'data_package.rtime' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

如果我在所有这些中手动输入 15 秒?空格,查询可以完美地使用日期作为参数。

1) 无论如何都要参数化间隔值(在这种情况下为 15),还是我只需要在它成为准备好的语句之前对其进行转义并搜索并替换它(如果这是真的,最好的转义方法是什么? Scala/Java 中的那个参数)

2) 我可以避免重复 dateadd(datediff()) 部分三次吗?我知道我不能在 WHERE 子句中引用“时间”,但是有没有其他方法可以在某个地方指定它以使其更清晰?

【问题讨论】:

    标签: java sql sql-server-2008 scala jdbc


    【解决方案1】:

    你的选择看起来像:

    SELECT dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) AS time,
    

    还有你的小组:

    GROUP BY dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0)
    

    ? 替换为常量,这两个是相同的。

    但是使用未命名的参数会带来一个问题。选择版本使用参数 1 和 2,按版本分组使用参数 9 和 10。而且 SQL Server 现在不会因为这些参数始终相等。所以它会抛出一个错误。

    您可以通过计算子查询中的字段来避免这种情况:

    left join
            (
            select  *
            ,       dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) as X
            from    data_package
            ) as pak
    on      dat.package_id = pak.id
    

    您现在可以在查询的其他部分引用pak.X,例如:

    group by
            pak.X
    

    【讨论】:

    • 不用子查询,派生表就可以了
    • @a_horse_with_no_name:派生表和子查询有什么区别?
    【解决方案2】:

    Andomar 说得对,问题在于 GROUP BY 中参数的使用,但我相信他的解决方案可能过于复杂。我认为更容易写:

    SELECT
      'UTC' AS timezone,
      rel.unique_id AS relay,sns.unique_id AS sensor,
      dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) AS time,
      SUM(CONVERT(FLOAT,dat.data)) AS total
      FROM sensor_data dat
       LEFT OUTER JOIN data_package pak ON dat.package_id = pak.id
       LEFT OUTER JOIN relays rel ON pak.relay_id = rel.id
       LEFT OUTER JOIN sensors sns ON dat.sensor_id = sns.id
       LEFT OUTER JOIN sensor_types typ ON sns.sensor_type = typ.id
       WHERE typ.name = 'Volume' AND dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) > ? AND dateadd(MINUTE, datediff(MINUTE, 0, pak.rtime) / ? * ?, 0) < ?
       GROUP BY rel.unique_id,sns.unique_id, time
       ORDER BY time,relay,sensor
    

    (另一方面,由于在您的特定情况下,您在 WHERE 中使用完全相同的表达式,也许子查询 更好。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-04
      • 2013-05-05
      • 2016-04-08
      • 2012-11-20
      • 2017-05-07
      • 2013-08-25
      • 2014-04-14
      • 1970-01-01
      相关资源
      最近更新 更多