2016-10-05 5 views
0

postgres 데이터베이스를 사용하고 있는데 문제가 두 개 포함되어 있습니다. 간체 버전은 아래에 나와 있습니다.PostgreSQL INSERT with statements

CREATE TABLE events(
    id SERIAL PRIMARY KEY NOT NULL, 
    max_persons INTEGER NOT NULL 
); 

CREATE TABLE requests(
    id SERIAL PRIMARY KEY NOT NULL, 
    confirmed BOOLEAN NOT NULL, 
    creation_time TIMESTAMP DEFAULT NOW(), 
    event_id INTEGER NOT NULL /*foreign key*/ 
); 

n 이벤트가 있고 각 이벤트는 최대 events.max_persons 참가자를 가질 수 있습니다. 새로운 요청을 확인해야하며 최대 30 분까지 유효합니다. 이 기간이 지나면 확인되지 않은 요청은 무시됩니다.

지금 내가 확인 모든 확인 요청과 여전히 유효 모든 요청하지만,하지의 합이, events.max_persons 미만 때만 새로운 request를 삽입한다를 수행 할 작업.

이미 단일 이벤트를 선택하는 쿼리가 있습니다. 명령을 - 여기의 단순화 된 버전은 그것이 하나의 INSERT와이를 달성하기 위해 possibile가

SELECT 
    e.id, 
    SUM(CASE WHEN r.confirmed = 1 THEN 1 ELSE 0 END) AS number_confirmed 
    SUM(CASE WHEN r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE') AND r.confirmed = 0 THEN 1 ELSE 0 END) AS number_reserved, 
    e.max_persons 
FROM events e, requests r 
WHERE l.id = ? 
    AND r.event_id = e.id    
    AND (r.confirmed = 1 OR r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE')) 
GROUP BY e.id, e.max_persons    
HAVING SUM(CASE WHEN r.confirmed = 1 OR (r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE')) THEN 1 ELSE 0 END) < e.max_persons"; 

작동하는 방법, 당신에게 아이디어를주고, 무엇입니까?

INSERT INTO requests 
    SELECT * FROM (VALUES (...)) row 
     WHERE ... 

을하고 조건이 만족 될 경우에만 참인 WHERE 절을 쓰기 :

답변

2

이 같은 것을 할 수 있습니다.

그러나이 접근법에는 근본적인 문제가 있습니다. 즉, 경쟁 조건이 적용됩니다.

두 개의 명령문이 동시에 실행되는 경우 모두 만족 된 조건을 찾을 수 있지만 각 행이 추가되고 커밋되면 조건을 위반할 수 있습니다. 왜냐하면 어떤 명령문도 커밋하기 전에 다른 명령문의 효과를 볼 수 없기 때문입니다. 테스트하고 삽입하기 전에

  • 테이블 잠금 :

    이 두 가지 솔루션이 있습니다. 그것은 간단하지만 동시성에 매우 나쁜 것입니다.

  • 전체적으로 SERIALIZABLE 트랜잭션을 사용하십시오. 그런 다음 직렬화 오류가 발생해야하며 명령문 중 하나를 다시 시도해야하며 그렇지 않을 경우 조건을 위반 한 것으로 간주합니다.

+0

안녕하십니까, 늦게 답변드립니다. 현재 max_persons와 number_booked/number_reserved의 차이점을 가져 오는 쿼리를 실행하여 내 문제를 해결하고 0보다 크면 insert 문만 실행합니다. 실용적인 방법입니까? 그리고 또 다른 질문, 내가 SERIALIZABLE 트랜잭션을 사용하는 경우 두 사람이 동시에 같은 이벤트에 등록하려고 할 때와 같은 문제가 있지만 한 곳만 남았습니다. – PrototypeX7

+0

현재의 기술은 내가 대답 한 문제에 취약합니다. 두 개의 트랜잭션이 병렬로 실행되고 한 곳만 비어 있으면 둘 다 새 요청을 추가합니다. 일어날 수없는 SERIALIZABLE. 트랜잭션 중 하나가 직렬화 오류로 종료되고 다시 시도해야합니다. 다시 시도하는 동안 이벤트가 이미 예약되었음을 나타냅니다. –

+0

감사합니다. 시도해보세요! – PrototypeX7