2012-05-05 3 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"

Так мне было интересно, как бы я исправить эту проблему, я не знаю, как форматировать дату правильно

EDIT:

Я звоню запрос, как этот

  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 not in (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 Подробнее о конвертации даты форматы). Формат ввода, который вы используете, должен работать очень хорошо, хотя (например, попробуйте 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 отметил в комментарии, общий запрос не будет работать в любом случае из-за ваш внутренний выбор.)

+0

У меня было трудное время, сортируя сравнение даты в PGSql при вызове хранимой функции из Java-кода. Простое сравнение дат даже не происходило. Даже не с подготовленным оператором, следующий запрос не выполнялся при вызове из класса java.Select * from tbl_name где 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, который намного быстрее.

  • Возвращение из plpgsql функции с RETURN QUERY - проще и быстрее, чем цикл.
  • Или используйте простое sql function.

Любой вариант имеет свои преимущества.