查询Firebird 3.0中的变量

问题描述

查询无效

select a.id from users a where a.LOGIN = 'Test' into :useriden
WITH T AS (
SELECT
   ID,FIO,PWDHASH,ATTIME,ROW_NUMBER() OVER(ORDER BY ATTIME DESC) AS RN
FROM USERSPWDHASHHISTORY
WHERE USERID = :useriden)
SELECT
   ID,ATTIME
FROM T
WHERE RN > 3

如何正确初始化数据库查询中的变量?不在存储过程或触发器中。

解决方法

所需的操作无法在DSQL中完成,而在PSQL中,这至少是语法错误,因为您不是要终止语句。

但是,您不需要单独的语句,可以内联查询

WITH T AS (
SELECT
   ID,FIO,PWDHASH,ATTIME,ROW_NUMBER() OVER(ORDER BY h.ATTIME DESC) AS RN
FROM USERSPWDHASHHISTORY
WHERE USERID = (select a.id from users a where a.LOGIN = 'Test'))
SELECT
   ID,ATTIME
FROM T
WHERE RN > 3

或使用联接而不是子查询

WITH T AS (
SELECT
   h.ID,h.FIO,h.PWDHASH,h.ATTIME,ROW_NUMBER() OVER(ORDER BY ATTIME DESC) AS RN
FROM USERSPWDHASHHISTORY h
inner join users u on h.userid = u.id
WHERE u.LOGIN = 'Test')
SELECT
   ID,ATTIME
FROM T
WHERE RN > 3

或者,您首先选择ID,然后使用?参数占位符为ID准备另一个查询,并使用先前选择的ID值准备并执行它。

例如,在Java中,您可以执行以下操作:

int id = -1;
try (var stmt = connection.createStatement();
     var rs = rs.executeQuery("select a.id from users a where a.LOGIN = 'Test'")) {
    if (rs.next()) {
        id = rs.getInt(1);
    }
}
try (var stmt = connection.prepareStatement("""
        WITH T AS (
        SELECT
           ID,ROW_NUMBER() OVER(ORDER BY ATTIME DESC) AS RN
        FROM USERSPWDHASHHISTORY
        WHERE USERID = ?)
        SELECT
           ID,ATTIME
        FROM T
        WHERE RN > 3
        """)) {

    stmt.setInt(1,id);
    try (var rs = stmt.executeQuery()) {
        // process result set
    }
}

但是,鉴于此特定示例可以在一条语句中完成,鉴于执行两条语句和相关网络往返的不必要开销,这种解决方案不是首选。