2011-12-29 3 views
2

나는 사용자가 VIP ("매우 중요한 사람")을 구매할 수있는 작은 게임 상태가로 :타임 스탬프를 확인하는 것은 null의 경우, 또는 PostgreSQL을 8.4.9에서 지난

# \d pref_users; 
       Table "public.pref_users" 
    Column |   Type    | Modifiers 
------------+-----------------------------+--------------- 
id   | character varying(32)  | not null 
vip  | timestamp without time zone | 

VIP는 적이있는 경우 구입 한 경우 NULL이됩니다.

vip이 만료 된 경우 < CURRENT_TIMESTAMP이됩니다.

create or replace function pref_move_week(_from varchar, 
    _to varchar) returns void as $BODY$ 
     declare 
       has_vip boolean; 
     begin 

     select vip > current_timestamp + interval '1 week' 
     into has_vip from pref_users where id=_from; 

     if (not has_vip) then 
       return; 
     end if; 

     update pref_users set vip = current_timestamp - interval '1 week' where id=_from; 
     update pref_users set vip = current_timestamp + interval '1 week' where id=_to; 

     end; 
$BODY$ language plpgsql; 

불행하게도이 절차가 작동하지 않습니다 내가 충분히 VIP 상태를 사용자에게 허용하는 PL/pgSQL의 절차를 만들려고 해요

는 "선물"로, 다른 사용자에게 일주일을주고 떠났다 주는 사용자의 VIP가 NULL 인 경우 적절하게 :

# update pref_users set vip=null where id='DE16290'; 
UPDATE 1 

# select id,vip from pref_users where id in ('DE16290', 'DE1'); 
    id |   vip 
---------+---------------------------- 
DE1  | 2012-01-05 17:35:17.772043 
DE16290 | 
(2 rows) 

# select pref_move_week('DE16290', 'DE1'); 
pref_move_week 
---------------- 

(1 row) 

# select id,vip from pref_users where id in ('DE16290', 'DE1'); 
    id |   vip 
---------+---------------------------- 
DE1  | 2012-01-05 17:43:11.589922 
DE16290 | 2011-12-22 17:43:11.589922 
(2 rows) 

e 위의 IF- 문구가 작동하지 않는 것으로 보입니다.

has_vip 변수가 여기에 전혀 필요하지 않은지 궁금합니다.

어떻게 나는 차 키 _from이 _topref_users 테이블에 실제로 존재 또는이 이미 알아서 있는지 확인 할 수합니다 (UPDATE 중 하나 문은 "예외가 발생하기 때문에 "트랜잭션이 롤백됩니다)?

UPDATE :

모든 답변 주셔서 감사하고 나는 또한 사용 팁을 가지고 :

  if (not coalesce(has_vip, false)) then 
        return; 
      end if; 

을하지만 지금은 새로운 문제가 있습니다

# select id,vip from pref_users where id in ('DE16290', 'DE1'); 
    id |   vip 
---------+---------------------------- 
DE1  | 2012-01-05 17:43:11.589922 
DE16290 | 
(2 rows) 

(즉, DE1은 5 월까지 VIP가 있고 DE16290에 일주일을 줄 수 있어야합니다.) :

# select pref_move_week('DE1', 'DE16290'); 
pref_move_week 
---------------- 

(1 row) 

# select id,vip from pref_users where id in ('DE16290', 'DE1'); 
    id |   vip 
---------+---------------------------- 
DE1  | 2012-01-05 17:43:11.589922 
DE16290 | 
(2 rows) 

(어떤 이유로 아무것도 변경되었습니다 들어?)

업데이트 2 : 최종 솔루션 -

create or replace function pref_move_week(_from varchar, 
     _to varchar) returns void as $BODY$ 
      begin 

      select 1 from pref_users 
       where id=_from and 
       vip > current_timestamp + interval '1 week'; 

      if not found then 
        return; 
      end if; 

      update pref_users set 
       vip = vip - interval '1 week' 
       where id=_from; 

      update pref_users set 
       vip = greatest(vip, current_timestamp) + interval '1 week' 
       where id=_to; 

      end; 
    $BODY$ language plpgsql; 

답변

1

Null 값은 다음과 같은 비교 단점에 대해 false를 반환합니다. null <> 1이 false이고 null = 1이 false 인 경우null는 동일하지 않거나 아무것도 동등하지 않음). 대신

if (not has_vip) then return 

if (not has_vip) or has_vip is null then return 

사용하는 구문과 함께 할 것입니다 여기에 약간의 고유하고 난 당신이 아닌 다른 배경에서 왔어요 추측 ... 그것을 읽기에 익숙하지 않아요 SQL과 아직 null 재미를 발견하지 못했습니다. Null은 다르게 처리해야하는 SQL의 특별한 개념입니다. 그것은 공백 또는 0과 같지 않으며 어떤 숫자보다 작거나 같지 않습니다. 나는이 혼란 조금 해요 :에

편집 어쨌든 희망

select vip 
    into has_vip from pref_users 
    where id=_from 
    and vip > current_timestamp + interval '1 week'; 

:

select vip > current_timestamp + interval '1 week' 
    into has_vip from pref_users where id=_from; 

나는이 동등하다 생각합니다. 이제 레코드가 없거나 VIP 값이 null 인 경우 null을 반환합니다. has_vip이 null이고 반환되면 그냥 갈 수 있습니까?

+0

고마워요 - 네, Perl, PHP, Java, C에서 경험이 있습니다 -하지만 SQL을 사용해야 할 때마다 (기본 선택/업데이트/삭제 명령문 외) 나는 많은 어려움을 겪고 물어볼 필요가 있습니다. 업데이트 된 질문에 대한 조언이 필요하십니까? –

+1

내 대답을 편집했습니다 ... 내가 그 논리를 올바르게 따라 왔다고 가정하면, VIP가 null이면 다시 빠져 나갈 수 있다고 생각합니다. 다소 재미있다. 만일 has_vip이 아니라면 나에게 혼란 스럽다. – Twelfth

+0

당신의 방법은 더 낫습니다, 고마워요. –

1

더 우아한 해결책이있을 수 있습니다하지만 난

SELECT (vip IS NOT NULL) AND (vip > current_timestamp + interval '1 week') 
생각

이 작업을 수행합니다. 당신의 문제는 NULL이 참이거나 거짓이 아니라는 사실과 관련이 있다고 생각합니다.

the docs에서 자세한 정보를 확인할 수 있습니다.

+0

및 다른 솔루션을 "(has_vip IS NULL) 또는 NOT (has_vip)"할 것 같아요. – Arthur

+0

혼란 스러워요. IF ... THEN .... END IF 조건부, 맞습니까?)하지만 두 번째 제안에서 해당 키워드를 사용하지 마십시오? –

+1

사실 그것은 분명하지 않을 수도 있습니다. 나의 첫 번째 대답에서 나는 당신의 "select vip> current_timestamp + interval을 '1 주일'로 pref_users에서 has_vip으로 id = _from;이라고 언급했다." 당신이 정말로 원하는 것은 id = _from 인 pref_users에서 "select (vip IS NOT NULL) 및 (vip> current_timestamp + interval '1 week') has_vip입니다." 모든 경우에 부울을 반환합니다. vip이 null 인 경우 false이거나 null이 아니고 주일이 아닌 경우 false입니다. null가 아닌 경우, 1 주일 후에 true가됩니다. 실제로이 질문은 귀하의 질문에 대한 답변입니다. "vip IS NOT NULL"부분은 bool을 반환합니다. – Arthur

2

타임 스탬프를 null 일 수있는 것과 비교할 때 COALESE 함수를 사용하여 비교할 "기본값"값을 제공 할 수 있습니다. 예를 들어,

select 1 from pref_users 
    where id=_from and 
    vip > COALESCE(current_timestamp, to_timestamp(0)); 

COALESCE 함수는 목록에서 첫 번째 비 - 널을 반환한다. docs을 참조하십시오. (또한 to_timestamp() 워드 프로세서 ...)