2012-05-05 191 views
2

我有以下格式化日期PostgreSQL的

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) 
); 

和我m試圖解析一個日期到函數,所以它可以爲我返回一個表,我似乎遇到了日期格式問題(這就是爲什麼我想我得到這個錯誤)

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將無法讀取它

+2

不清楚爲什麼你需要首先解析或格式化。輸入來自哪裏,你如何調用函數? –

+1

此聲明:'..其中r.id不在(select * from ...)中'是無效的SQL。您必須在子選擇中選擇一個列。 –

+0

@a_horse_with_no_name,好點,我沒有真正閱讀查詢本身的細節。我覺得沒有這個功能,可以做得更好。 – Bruno

回答

3

這聽起來像你通過將它們直接連接到字符串來傳遞參數。這是一個非常糟糕的主意,因爲它可能導致SQL注入。總是use 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的手冊上的日期轉換細節格式)。您正在使用的輸入格式應該可以正常工作,但(例如,直接在PostgreSQL中嘗試SELECT CAST('2012-05-01' AS DATE),這將返回正確的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在評論中指出,一般的查詢不會工作,無論如何,因爲你內心的選擇。)

+0

我在從Java代碼中調用存儲函數的同時在PGSql中整理出日期比較的過程非常艱難。簡單的日期比較甚至沒有發生。甚至沒有準備好的語句,當從java class中調用時,下面的查詢沒有運行。選擇* from tbl_name where field_name Ankur

2

this page,在SQL日期/時間字符串的標準格式是:

YYYY-MM-DD HH:MM:SS 

課程日期,你也可以使用

YYYY-MM-DD 

的PostgreSQL接受其他格式(見here爲一些細節),但沒有理由不堅持標準。

然而,因爲你得到一個語法錯誤這聽起來像你注射日期字符串到您的SQL語句,如果沒有適當的報價/轉義。仔細檢查你是否正確地逃脫了你的輸入。

+0

請鏈接到[當前版本的手冊](http://meta.stackexchange.com/q/108714/169168)。 –

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語句是要快得多。

  • 返回從RETURN QUERY一個PLPGSQL功能 - 更簡單,比循環更快。
  • 或使用普通的sql函數。

無論哪種變型都有其優點。