Project: YugabyteDB (App Definition and Development / Database)
File: if-statement.md

title: The "if" statement [YSQL] headerTitle: The "if" statement linkTitle: The "if" statement description: Describes the syntax and semantics of the PL/pgSQL "if" statement. [YSQL]. menu: stable: identifier: if-statement parent: compound-statements weight: 20 type: docs showRightNav: true {{%ebnf%}} plpgsqlifstmt, plpgsqlelsifleg {{%/ebnf%}} 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 guardexpressionand each is tested in turn, in the order in which they are written. When a guardexpression evaluates to false, the point of execution immediately moves to the next guardexpression, skipping the statement list that it guards. As soon as a guardexpression 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 statementskipping the evaluation of any remaining guardexpressions. This economical testing of the guardexpressions 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 executedor 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 guardexpressions_ 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 searchpath = pgcatalog, 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

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 name="case-stmt-versus-if-stmt"></a> {{< tip title="A 'case' statement is often a better choice than an 'if' statement." >}} See the 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 searchpath = pgcatalog, 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 falt() 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 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 guardexpressions, that if none of these evaluates to true, then the casenotfound_ 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. {{< /tip >}}