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インジェクションにつながる可能性があるため、非常に悪い考えです。パラメータを渡すには、常にプレースホルダーとともにsを使用PreparedStatement?します。クエリ文字列に直接連結してパラメータを直接渡すことは絶対にしないでください(さらに、'区切り文字が必要になります)。

あなたは次のようなものを持つことができます:

 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)またはを使用して文字列をキャストする必要があり'...'::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

このページによると、SQLの日付/時刻文字列の標準形式は次のとおりです。

YYYY-MM-DD HH:MM:SS

そしてもちろん、あなたが使用できる日付のために

YYYY-MM-DD

PostgreSQLは他のフォーマットを受け入れます(詳細についてはここを参照)が、標準に固執しない理由はありません。

ただし構文エラーが発生しているため、適切な引用符/エスケープなしでSQLステートメントに日付文字列を挿入しているように聞こえます。入力を適切にエスケープしていることを再確認してください。

于 2012-05-05T11:59:26.137 に答える