2

我有以下

DateFormat dformat = new SimpleDateFormat("yyyy-M-d");
            dformat.setLenient(false);
            Date cin = dformat.parse(cinDate);

和sql函数

create or replace function search(_checkIn date, _checkOut date) returns setof Bookings as $$
declare
    r Bookings;
begin
    for r in
    select * from Bookings
    loop
        if ((_checkIn between r.checkIn and r.checkOut) or (_checkOut between r.checkIn and r.checkOut)) then
            return next r;
        end if;
    end loop;
    return;
end;
$$ language plpgsql;

postgresql 的日期格式是标准的(默认)

create table Bookings (
    id          serial,
    status      bookingStatus not null,
    pricePaid   money not null,
    firstName   text,
    lastName    text,
    address     text,
    creditCard  text,
    checkOut    date not null,
    checkIn     date not null,
    room        integer not null,
    extraBed    boolean not null default false,

    foreign key (room) references Rooms(id),
    primary key (id)
);

我正在尝试将日期解析到函数中,以便它可以为我返回一个表,我似乎遇到了日期格式的问题(这就是我认为我收到此错误的原因)

org.postgresql.util.PSQLException: ERROR: syntax error at or near "Feb"

所以我想知道如何解决这个问题,我不知道如何正确格式化日期

编辑:

我正在调用这样的查询

           try {
                String searchQuery = "SELECT * FROM Rooms r where r.id not in (select * from search(" + cin +", " + cout +"))";
                PreparedStatement ps = conn.prepareStatement(searchQuery);
                rs = ps.executeQuery();
            } catch (SQLException e) {
                e.printStackTrace();
            }

所以我认为出现错误是因为我格式化日期的方式是错误的,postgres 不会读取它

4

3 回答 3

3

听起来您通过将参数直接连接到字符串中来传递参数。这是一个非常糟糕的主意,因为它可能导致 SQL 注入。始终PreparedStatements?占位符一起使用来传递参数,切勿通过将它们直接连接到查询字符串中来直接传递它们(更重要的是,您需要'周围的分隔符)。

你可以有类似的东西:

 PreparedStatement stmt
     = con.prepareStatement("SELECT id FROM Bookings WHERE checkIn=?")
 stmt.setDate(1, new java.sql.Date(cin.getTime()));
      // ? parameters are indexed from 1
 ResultSet results = stmt.executeQuery();

或者,PostgreSQL 内部日期转换通常相当好和灵活。您可以使用 PostgreSQL 将字符串参数转换为日期:

 PreparedStatement stmt
     = con.prepareStatement("SELECT id FROM Bookings WHERE checkIn=CAST(? AS DATE)");
 stmt.setString(1, cinDate);
 ResultSet results = stmt.executeQuery();

这是灵活的,但可能不会导致您需要的确切结果,具体取决于日期格式(您可以查看 PostgreSQL 手册以获取有关日期转换格式的详细信息)。不过,您使用的输入格式应该可以正常工作(SELECT CAST('2012-05-01' AS DATE)例如,直接在 PostgreSQL 中尝试,这将返回正确的 PostgreSQL 日期。)

请注意,使用 时new java.sql.Date(cin.getTime()),您可能会遇到时区问题。你也可以用java.sql.Date.valueOf(...)

为了澄清,在您的编辑之后:

这不起作用,因为日期将是 SQL 语法本身的一部分,而不是字符串或日期:"SELECT * FROM Rooms r where r.id not in (select * from search(" + cin +", " + cout +"))"

您至少需要使用'引号:"SELECT * FROM Rooms r where r.id not in (select * from search("' + cin +"', '" + cout +"'))". 在这里,在某种程度上,您可以期望参数格式正确,但不要这样做。此外,仍然需要使用CAST('...' AS DATE)or来转换字符串'...'::DATE

最简单的方法当然是:

String searchQuery = "SELECT * FROM Rooms r where r.id not in (select SOMETHING from search(CAST(? AS DATE), CAST(? AS DATE)))";
PreparedStatement ps = conn.prepareStatement(searchQuery);
ps.setString(1, cinDate);
ps.setString(2, coutDate);

(正如 a_horse_with_no_name 在评论中指出的那样,由于您的内部选择,一般查询无论如何都不起作用。)

于 2012-05-05T11:59:56.940 回答
3

您已经获得了有关准备好的陈述和正确格式的建议。

您还可以在很大程度上简化您的 PostgreSQL 函数:

CREATE OR REPLACE FUNCTION search(_checkin date, _checkout date)
  RETURNS SETOF bookings AS
$BODY$
BEGIN
    RETURN QUERY
    SELECT *
    FROM   bookings
    WHERE  _checkin BETWEEN checkin AND checkout
       OR  _checkiut BETWEEN checkin AND checkout;

END;
$BODY$ language plpgsql;

甚至:

CREATE OR REPLACE FUNCTION search(_checkin date, _checkout date)
  RETURNS SETOF bookings AS
$BODY$
    SELECT *
    FROM   bookings
    WHERE  _checkin BETWEEN checkin AND checkout
       OR  _checkiut BETWEEN checkin AND checkout;
$BODY$ language sql;

将加号条件重写LOOP为更快的普通 SQL 语句。

  • plpgsql函数返回RETURN QUERY- 比循环更简单、更快。
  • 或者使用普通的sql函数。

任何一种变体都有其优点。

于 2012-05-05T14:19:10.310 回答
2

根据this page,SQL中日期/时间字符串的标准格式是:

YYYY-MM-DD HH:MM:SS

当然,对于您可以使用的日期

YYYY-MM-DD

PostgreSQL 接受其他格式(有关详细信息,请参见此处),但没有理由不遵守标准。

但是,由于您遇到语法错误,因此听起来您将日期字符串注入 SQL 语句而没有正确的引用/转义。仔细检查您是否正确地转义了您的输入。

于 2012-05-05T11:59:26.137 回答