---
title: "The \"if\" statement"
url: "https://docs.yugabyte.com/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/"
---

# The "if" statement

Describes the syntax and semantics of the PL/pgSQL "if" statement. [YSQL].

## Syntax

- [![Grammar Icon](/icons/file-lines.svg)Grammar](#grammar-1)
- [![Diagram Icon](/icons/diagram.svg)Diagram](#diagram-1)

```output.ebnf
plpgsql_if_stmt ::= IF guard_expression THEN 
                    [ plpgsql_executable_stmt [ ... ] ]  
                    [ plpgsql_elsif_leg [ ... ] ]  
                    [ ELSE [ plpgsql_executable_stmt [ ... ] ] ]  END 
                    IF

plpgsql_elsif_leg ::= { ELSIF | ELSEIF } guard_expression THEN 
                      [ plpgsql_executable_stmt [ ... ] ]
```

#### plpgsql\_if\_stmt

IF[guard\_expression](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/syntax_resources/grammar_diagrams#guard-expression)THEN[plpgsql\_executable\_stmt](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/syntax_resources/grammar_diagrams#plpgsql-executable-stmt)[plpgsql\_elsif\_leg](#plpgsql-elsif-leg)ELSE[plpgsql\_executable\_stmt](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/syntax_resources/grammar_diagrams#plpgsql-executable-stmt)ENDIF

#### plpgsql\_elsif\_leg

ELSIFELSEIF[guard\_expression](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/syntax_resources/grammar_diagrams#guard-expression)THEN[plpgsql\_executable\_stmt](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/if-statement/syntax_resources/grammar_diagrams#plpgsql-executable-stmt)

## Semantics

The *if* statement lets you specify one or several lists of executable statements so that a maximum of one of those lists will be selected. Each list is guarded by a *boolean* *guard\_expression*—and each is tested in turn, in the order in which they are written. When a *guard\_expression* evaluates to *false*, the point of execution immediately moves to the next *guard\_expression*, skipping the statement list that it guards. As soon as a *guard\_expression* evaluates to *true*, the statement list that it guards is executed; and on completion of that list, control passes to the first statement after the *end if* of the *if* statement—skipping the evaluation of any remaining *guard\_expressions*. This economical testing of the *guard\_expressions* is common to many programming languages. It is a particular example of so-called short-circuit evaluation.

Here is the template of the simplest *if* statement:

```plpgsql
if <guard_expression> then
  <guarded statement list>
end if;
```

While you're typing in your code, you might like to omit the statement list altogether. Doing so causes neither a syntax error nor a runtime error. The omission is equivalent to the single *"null;"* statement.

The simplest *if* statement pattern, above, is very common and useful. The guarded statement list is either executed—or skipped. But consider an example when there are two or more alternative statement lists, like this:

```plpgsql
if <guard_expression 1> then
  <guarded statement list 1>
elsif <guard_expression 2> then
  <guarded statement list 2>
end if;
```

There are two possibilities here:

- *either* the set of *guard\_expressions* jointly covers all possibilities
- *or* it might not cover all possibilities.

However, it's generally hard for the reader to work out whether or not all possibilities are covered. Therefore it's hard for the reader to know whether the programmer intended:

- *either* to handle every possibility explicitly, but simply forgot one or several possibilities
- *or* to do nothing for the possibilities without an explicit test.

The better approach, therefore, is always to include the bare *else* leg in an *if* statement that has two or more guard expressions. The intention is advertised clearly by writing the *null* statement (or maybe by raising a user-defined exception) in the *else* leg.

Try this:

```plpgsql
\c :db :u
drop schema if exists s cascade;
create schema s;

create function s.f(i in int)
  returns table(z text)
  set search_path = pg_catalog, pg_temp
  language plpgsql
as $body$
begin
  if i < 0 then
    z := 'i < 0'; return next;
  elsif i > 0 then
    z := 'i > 0'; return next;
  elsif i = 0 then
    z := 'i = 0'; return next;
  else
    raise exception using
      errcode := 'YB123',
      message := 'Unexpected. "i" must not be "null".';
  end if;
end;
$body$;

select s.f(1);
select s.f(-1);
select s.f(0);
```

These are the results. First:

```output
 i > 0
```

And then:

```output
 i < 0
```

And then:

```output
 i = 0
```

Now try the negative test:

```plpgsql
select s.f(null);
```

It causes the user-defined *YB123* error:

```output
Unexpected. "i" must not be "null".
CONTEXT:  PL/pgSQL function s.f(integer) line 10 at RAISE
```



A 'case' statement is often a better choice than an 'if' statement.

See the [*case* statement](/stable/api/ysql/user-defined-subprograms-and-anon-blocks/language-plpgsql-subprograms/plpgsql-syntax-and-semantics/executable-section/compound-statements/case-statement "case statement") section. The example can be re-written as a *case* statement. In the present scenario, when you want to raise an exception if, unexpectedly, *i* is *null*, you can rely on the *case* statement's native functionality and simply omit the *else* leg, thus:

```plpgsql
create function s.f_alt(i in int)
  returns table(z text)
  set search_path = pg_catalog, pg_temp
  language plpgsql
as $body$
begin
  case
    when  i < 0 then
      z := 'i < 0'; return next;
    when i > 0 then
      z := 'i > 0'; return next;
    when i = 0 then
      z := 'i = 0'; return next;
  end case;
end;
$body$;

select s.f_alt(1);
select s.f_alt(-1);
select s.f_alt(0);
```

The results so far are identical to those for the *if* statement alternative.

Now try the negative test:

```plpgsql
select s.f_alt(null);
```

It causes the *20000* error:

```output
case not found
HINT:  CASE statement is missing ELSE part.
CONTEXT:  PL/pgSQL function s.f_alt(integer) line 3 at CASE
```

If you can be sure that *i* will never be *null* (or *should* never be, as long as the surrounding code environment is bug-free) then *f\_alt()* is a better choice than the original *f()* because it more clearly, and more tersely, conveys the intention to the reader. (You must assume that the reader understands the *case* statement semantics.)

If, rather, you know that *i* might be *null* and know what to do in this case, you can simply add another [*plpgsql\_searched\_when\_leg*](/stable/api/ysql/syntax_resources/grammar_diagrams/#plpgsql-searched-when-leg "plpgsql_searched_when_leg"):

```plpgsql
case
  when  i < 0 then
    z := 'i < 0'; return next;
  when i > 0 then
    z := 'i > 0'; return next;
  when i = 0 then
    z := 'i = 0'; return next;
  when i is null then
    <appropriate action for this case>
end case;
```

This is the critical difference:

- The *case* formulation tells the reader, without requiring analysis of the *guard\_expressions*, that if none of these evaluates to *true*, then the *case\_not\_found* error will be raised.
- The *if* formulation requires the reader to look at the joint effect of all the tests in order to determine if they do, or do not, cover all possible values of *i*.

Notice that, should *i* be a user-defined domain with a composite base type and user-defined `>`, `<`, and `=` operators that allow comparison with *int* values, the analysis task could be difficult.

Programmers argue about their preferences for the choice between an *if* statement and a *case* statement.
