代码之家  ›  专栏  ›  技术社区  ›  Yossale

如果不为空,则比较日期

  •  2
  • Yossale  · 技术社区  · 5 年前

    我需要找到所有带有create date>x的记录。x是一个sql.timestamp,可能为空,在这种情况下,我只想返回所有记录。所以我试着:(createdafter是时间戳)

    SELECT *
    FROM sample AS s
    WHERE s.isActive
      AND (:createdAfter ISNULL OR s.insert_time > :createdAfter)
    

    但我得到的只是

    org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $1
    

    但是,如果我在检查任意int是否为空时执行相同的查询:

    SELECT * 
    FROM trades 
    WHERE (:sInt ISNULL OR trades.insert_time > :createdAfter ) 
    

    那就行了。发生了什么?

    2 回复  |  直到 5 年前
        1
  •  0
  •   pirho    5 年前

    如果您想坚持使用这种本机查询,就没有简单的解决方案。这个 null 值转换为 bytea 价值。例如,请参见 this this

    这个价值很难被铸造或与 timestamp 价值。

    问题不在于第一次比较,而是通过使用coalesce来处理,比如:

    COALESCE(:createdAfter) ISNULL
    

    因为在实际值和数据类型之间没有比较。但是比较

    sometimestamp::timestamp > null::bytea (强制转换只是为了显示不起作用的实际类型)

    可能需要更多的逻辑支持过程和异常处理,不确定。

    因此,如果JPQL或CriteriaQueries不可能用于您,则只有错误的选项:

    • 通过字符串连接或左右设置参数来构造查询(不是!不确定真的有用吗)
    • 使用 PreparedStatement 查询,更多代码和工作
    • 如果使用hibernate,则使用 this answer
        2
  •  0
  •   George S    5 年前

    您可以尝试使用 pg_typeof 函数,返回文本字符串,并使用 CASE 强制进行比较的语句(否则不能保证postgres会以正确的顺序使or短路)。然后,您可以通过转换为文本,然后返回到时间戳,强制转换,这是不优雅的,但应该是有效的。

    SELECT *
    FROM sample AS s
    WHERE s.isActive
      AND 
        CASE WHEN pg_typeof( :createdAfter ) = 'bytea' THEN TRUE
           WHEN s.insert_time > ( ( :createdAfter )::text)::timestamp THEN TRUE
           ELSE FALSE 
        END