PL/SQL programing 第六版学习笔记-3

2020-11-26  本文已影响0人  e652d1fb12eb

Working with Program Data

1. Naming Your Program Data

2. Overview of PL/SQL Datatypes

Character Data

CHAR and NCHAR are fixed-length datatypes; VARCHAR2
and NVARCHAR2 are variable-length datatypes.

PL/SQL has the CLOB (character large object) and NCLOB (National Language Support CLOB) datatypes. For backward compatibility,PL/SQL also supports the LONG datatype. These datatypes allow you to store and manipulate very large amounts of data; in Oracle Database 11g, a LOB can hold up to 128 terabytes of information.

Numbers
/* File on web: numbers.sql */
DECLARE
  salary NUMBER(9,2); -- fixed-point, seven to the left, two to the right
  raise_factor NUMBER; -- decimal floating-point
  weeks_to_pay NUMBER(2); -- integer
BEGIN
  salary := 1234567.89;
  raise_factor := 0.05;
  weeks_to_pay := 52;
END;
Dates, Timestamps, and Intervals
Booleans
Binary Data

including RAW, BLOB, and BFILE.
for example, you try to fetch a LONG RAW from the database into your PL/SQL variable that exceeds the 32,760 byte limit, you will encounter an ORA-06502: PL/SQL: numeric or value error exception. To work with LONG RAWs longer than PL/SQL’s limit, you need an OCI program; this is a good reason to migrate your legacy code from LONG RAWs to BLOBs, which have no such limit.

ROWIDs

Oracle provides two proprietary datatypes, ROWID and UROWID, used to represent
the address of a row in a table. ROWID represents the unique physical address of a row
in its table; UROWID represents the logical position of a row in an index-organized
table (IOT). ROWID is also a SQL pseudocolumn that can be included in SQL statements.

REF CURSORs

The REF CURSOR datatype allows developers to declare cursor variables. A cursor
variable can then be used with static or dynamic SQL statements to implement more
flexible programs. There are two forms of REF CURSORs: the strong REF CURSOR
and the weak REF CURSOR. PL/SQL is a statically typed language, and the weak REF
CURSOR is one of the few dynamically typed constructs supported.
Here is an example of a strong REF CURSOR declaration. I associate the cursor variable with a specific record structure (using a %ROWTYPE attribute):

DECLARE
  TYPE book_data_t IS REF CURSOR RETURN book%ROWTYPE;
  book_curs_var book_data_t;

And here are two weak REF CURSOR declarations in which I do not associate any
particular structure with the resulting variable. The second declaration (the last line)
showcases SYS_REFCURSOR, a predefined weak REF CURSOR type:

DECLARE
  TYPE book_data_t IS REF CURSOR;
  book_curs_var book_data_t;
  book_curs_var_b SYS_REFCURSOR;
Internet Datatypes

XML (Extensible Markup Language) and URIs (universal resource identifiers).

“Any” Datatypes
User-Defined Datatypes

3. Declaring a Variable

The basic syntax for a declaration is:
name datatype [NOT NULL] [ := | DEFAULT default_assignment];

Declaring Constants

the syntax for the declaration of a constant is:
name CONSTANT datatype [NOT NULL] := | DEFAULT default_value;

Anchored Declarations

PL/SQL offers two kinds of anchoring:

Anchoring to Cursors and Tables

Suppose that I want to query a single row of information from the book table. Rather
than declare individual variables for each column in the table (which, of course, I should
do with %TYPE), I can simply rely on %ROWTYPE:

DECLARE
  l_book book%ROWTYPE;
BEGIN
  SELECT * INTO l_book FROM book WHERE isbn = '1-56592-335-9';
  process_book (l_book);
END;

Suppose now that I only want to retrieve the author and title from the book table. In

this case, I build an explicit cursor and then %ROWTYPE against that cursor:

DECLARE
  CURSOR book_cur IS
  SELECT author, title FROM book WHERE isbn = '1-56592-335-9';
  l_book book_cur%ROWTYPE;
BEGIN
  OPEN book_cur;
  FETCH book_cur INTO l_book; END;

Finally, here is an example of an implicit use of the %ROWTYPE declaration: the cursor FOR loop.

BEGIN
  FOR book_rec IN (SELECT * FROM book)
LOOP
  process_book (book_rec);
END LOOP;
END;
Benefits of Anchored Declarations

Programmer-Defined Subtypes

SUBTYPE POSITIVE IS BINARY_INTEGER RANGE 1 .. 2147483647;

SUBTYPE FLOAT IS NUMBER;

Conversion Between Datatypes

3. STRINGS

If you omit the CHAR or BYTE qualifier when declaring a VARCHAR2 variable, then
whether the size is in characters or bytes depends on the NLS_LENGTH_SEMANTICS
initialization parameter. You can determine your current setting by querying NLS_SESSION_PARAMETERS.

Prior to 12c, the maximum length of the CHAR datatype in SQL was 2,000; in 12c, this
is now increased to match the PL/SQL maximum: 32,767 bytes. Note, however, that SQL supports these maximum sizes only if the MAX_SQL_STRING_SIZE initialization parameter is set to EXTENDED.

It’s unlikely that you’ll ever need to use these—I never do—but you should be aware that they exist.


图片.png
Specifying String Constants

If you want to embed a single quote within a string constant, you can do so by typing
the single quote twice:

'Aren''t you glad you''re learning PL/SQL with O''Reilly?'

If your program will be dealing with strings that contain embedded single-quote characters,a more elegant approach is to specify your own string delimiters. Do this using the q prefix (uppercase Q may also be specified). For example:

q'!Aren't you glad you're learning PL/SQL with O'Reilly?!'
or:
q'{Aren't you glad you're learning PL/SQL with O'Reilly?}'

Occasionally, however, you may need to explicitly specify a string constant to be represented in the national character set. You can do so using the n prefix:

n'Pils vom faß: 1₠'

If you need a string in the national character set, and you also want to specify some
characters by their Unicode code point, you can use the u prefix:

u'Pils vom fa\00DF: 1\20AC'

00DF is the code point for the German letter ß, while 20AC is the code point for the
Euro symbol. The resulting string constant is the same as for the preceding n-prefixed
example.
When they encounter an ampersand,these tools “see” the next word as a variable and prompt you to supply a value:

SET SERVEROUT ON;
SET DEFINE OFF;
begin
    DBMS_OUTPUT.PUT_LINE ('Generating & saving test data.');
END;
/

There are several solutions to this problem. One that works well with SQL*Plus and
SQL Developer is to issue the command SET DEFINE OFF to disable the variable substitution feature.

You can do that by concatenating all the address lines together into one long text value
and using CHR to insert linefeeds where desired. The location in the standard ASCII
collating sequence for the linefeed character is 10, so you can code:

SELECT name || CHR(10) || address1 || CHR(10) || address2 || CHR(10) || city || ', ' || state || ' ' || zipcode AS company_address FROM company;

You say your boss doesn’t want to see any blank lines? No problem. You can
eliminate those with a bit of cleverness involving the NVL2 function:

SELECT name  || NVL2(address1, CHR(10) || address1, '') || NVL2(address2, CHR(10) || address2, '') || CHR(10) || city || ', ' || state || ' ' || zipcode AS company_address
FROM company;

Now the query returns a single formatted column per company. The NVL2 function
returns the third argument when the first is NULL, and otherwise returns the second
argument. In this example, when address1 is NULL, the empty string (‘’) is returned,
and likewise for the other address columns.
The ASCII function, in essence, does the reverse of CHR: it returns the decimal representation of a given character in the database character set. For example, execute the following code to display the decimal code for the letter J:

BEGIN
  DBMS_OUTPUT.PUT_LINE(ASCII('J'));
END;

and you’ll find that, in UTF-8 at least, the underlying representation of J is the value 74.

There are two mechanisms for concatenating strings: the CONCAT function and the
concatenation operator, represented by two vertical bar characters (||).
use the CONCAT function, which takes two arguments as follows:

CONCAT (string1, string2)

CONCAT ('abc', 'defg') --> 'abcdefg'
CONCAT (NULL, 'def') --> 'def'
CONCAT ('ab', NULL) --> 'ab'
CONCAT (NULL, NULL) --> NULL

To perform the identical concatenation using CONCAT, you would need to nest one
call to CONCAT inside another:

x := CONCAT(CONCAT('abc','def'),'ghi');

One way to deal with case issues is to use the built-in UPPER and LOWER functions.
These functions let you force case conversion on a string for a single operation. For
example:

DECLARE
  name1 VARCHAR2(30) := 'Andrew Sears';
  name2 VARCHAR2(30) := 'ANDREW SEARS';
BEGIN
  IF LOWER(name1) = LOWER(name2) THEN
  DBMS_OUTPUT.PUT_LINE('The names are the same.');
END IF;
END;

Initially the code is using the emp_name_ix index, but when I set NLS_COMP=LINGUISTIC
and NLS_SORT=BINARY_CI to enable case insensitivity I stop using the
index and start doing full table scans instead—oops! One solution is to create a functionbased,case-insensitive index, like this:

CREATE INDEX last_name_ci ON EMPLOYEES (NLSSORT(last_name, 'NLS_SORT=BINARY_CI'))

Now when I do my case-insensitive query, I use the case-insensitive index and keep my
good performance.

A third case-related function, after UPPER and LOWER, is INITCAP. This function forces the initial letter of each word in a string to uppercase, and all remaining letters to lowercase.

The INSTR function returns the character position of a substring within a larger string. The following code finds the locations of all the commas in a list of names:

DECLARE
  names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Aaron,Jeff';
  comma_location NUMBER := 0;
BEGIN
LOOP
  comma_location := INSTR(names,',',comma_location+1);
  EXIT WHEN comma_location = 0;
  DBMS_OUTPUT.PUT_LINE(comma_location);
END LOOP;
END;

The output is:
5
10
14
21
28
34

例如:INSTR('CORPORATE FLOOR','OR', 3, 2)中,源字符串为'CORPORATE FLOOR',在字符串中查找'OR',从第三个字符位置开始查找"OR",取第三个字后第2个匹配项的位置。

You can use LPAD and RPAD
to add spaces (or some other character) to either end of a string in order to make the
string a specific length.

DECLARE
  a VARCHAR2(30) := 'Jeff';
  b VARCHAR2(30) := 'Eric';
  c VARCHAR2(30) := 'Andrew';
  d VARCHAR2(30) := 'Aaron';
  e VARCHAR2(30) := 'Matt';
  f  VARCHAR2(30) := 'Joe';
BEGIN
  DBMS_OUTPUT.PUT_LINE( RPAD(a,10) || LPAD(b,10) );
  DBMS_OUTPUT.PUT_LINE( RPAD(c,10) || LPAD(d,10) );
  DBMS_OUTPUT.PUT_LINE( RPAD(e,10) || LPAD(f,10) );
END;

The output is:
Jeff Eric
Andrew Aaron
Matt Joe

The default padding character is the space. If you like, you can specify a fill character
as the third argument. Change the lines of code to read:

DBMS_OUTPUT.PUT_LINE( RPAD(a,10,'.') || LPAD(b,10,'.') );
DBMS_OUTPUT.PUT_LINE( RPAD(c,10,'.') || LPAD(d,10,'.') );
DBMS_OUTPUT.PUT_LINE( RPAD(e,10,'.') || LPAD(f,10,'.') );
And the output changes to:
Jeff............Eric
Andrew.........Aaron
Matt.............Joe

Your fill “character” can even be a string of characters:

DBMS_OUTPUT.PUT_LINE( RPAD(a,10,'-~-') || LPAD(b,10,'-~-') );
DBMS_OUTPUT.PUT_LINE( RPAD(c,10,'-~-') || LPAD(d,10,'-~-') );
DBMS_OUTPUT.PUT_LINE( RPAD(e,10,'-~-') || LPAD(f,10,'-~-') );

Now the output looks like:
Jeff-~--~--~--~-Eric
Andrew-~---~--~Aaron
Matt-~--~--~--~--Joe

What LPAD and RPAD giveth, TRIM, LTRIM, and RTRIM taketh away. For example:

DECLARE
  a VARCHAR2(40) := 'This sentence has too many periods......';
  b VARCHAR2(40) := 'The number 1';
BEGIN
  DBMS_OUTPUT.PUT_LINE( RTRIM(a,'.') );
  DBMS_OUTPUT.PUT_LINE(
    LTRIM(b, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz')
  );
END;
The output is:
This sentence has too many periods
1

The other trimming function is just plain TRIM. Oracle added TRIM when Oracle8i
Database was released in order to make the database more compliant with the ISO SQL standard. TRIM works a bit differently from LTRIM and RTRIM, as you can see:

DECLARE
  x VARCHAR2(30) := '.....Hi there!.....';
BEGIN
  DBMS_OUTPUT.PUT_LINE( TRIM(LEADING '.' FROM x) );
  DBMS_OUTPUT.PUT_LINE( TRIM(TRAILING '.' FROM x) );
  DBMS_OUTPUT.PUT_LINE( TRIM(BOTH '.' FROM x) );
  -- The default is to trim from both sides
  DBMS_OUTPUT.PUT_LINE( TRIM('.' FROM x) );
  -- The default trim character is the space:
  DBMS_OUTPUT.PUT_LINE( TRIM(x) );
END;

The output is:
Hi there!.....
.....Hi there!
Hi there!
Hi there!
.....Hi there!.....

Detecting a pattern
The general syntax for the REGEXP_LIKE function is:
REGEXP_LIKE (source_string, pattern [,match_modifier])

Locating a pattern
You can use REGEXP_INSTR to locate occurrences of a pattern within a string. The
general syntax for REGEXP_INSTR is:
REGEXP_INSTR (source_string, pattern [,beginning_position [,occurrence
[,return_option [,match_modifier [,subexpression]]]]])

Extracting text matching a pattern
I’ll use REGEXP_SUBSTR to extract a phone number from a string containing
contact information:

DECLARE
  contact_info VARCHAR2(200) := 'address:1060 W. Addison St.Chicago, IL 60613
    home 773-555-5253';
  phone_pattern VARCHAR2(90) :=
    '\(?\d{3}\)?[[:space:]\.\-]?\d{3}[[:space:]\.\-]?\d{4}';
BEGIN
  DBMS_OUTPUT.PUT_LINE('The phone number is: '||
  REGEXP_SUBSTR(contact_info,phone_pattern,1,1));
END;

This code shows me the phone number:
The phone number is: 773-555-5253

Oracle database treats empty strings as NULLs. This is contrary to the ISO SQL standard, which recognizes the difference between an empty string and a string variable that is NULL.

DECLARE
    empty_varchar2 VARCHAR2(10) := '';
    empty_char CHAR(10) := '';
BEGIN
    IF empty_varchar2 is null then
        DBMS_OUTPUT.PUT_LINE('empty_varchar2 is Null');
    end if;
    IF '' IS NULL THEN
        DBMS_OUTPUT.PUT_LINE(''''' is NULL');
    END IF;
    
    IF empty_char IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
    ELSIF empty_char IS NOT NULL THEN
        DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
    END IF;
END;

You’ll notice in this example that the CHAR variable is not considered NULL. That’s
because CHAR variables, as fixed-length character strings, are never truly empty.
a NULL is never not equal, or equal,to any other value.

Database-to-variable conversion When you SELECT or FETCH data from a CHAR database column into a VARCHAR2 variable, the trailing spaces are retained. If you SELECT or FETCH from a VARCHAR2 database column into a CHAR variable, PL/SQL automatically pads the value with spaces out to the maximum length. In other words, the type of the variable, not the column, determines the variable’s resulting value.

ASCII(single_character)

Returns the NUMBER code that represents the specified character in the database
character set.

ASCIISTR(string1)

Takes a string in any character set and converts it into a string of ASCII characters.
Any non-ASCII characters are represented using the form \XXXX, where
XXXX represents the Unicode value for the character.

CHR(code_location)

Returns a VARCHAR2 character (length 1) that corresponds to the location in the
collating sequence provided as a parameter. This is the reverse of ASCII.

COMPOSE(string1)

Takes a Unicode string as input and returns that string in its fully normalized
form.

CONCAT(string1, string2)

Appends string2 to the end of string1. You’ll get the same results as from the expression string1 || string2. I find the || operator so much more convenient
that I almost never invoke the CONCAT function.

CONVERT(string1, target_char_set)

Converts a string from the database character set to the specified target character
set. You may optionally specify a source character set:
CONVERT(string1, target_char_set, source_character_set)

DECOMPOSE(string1)

Takes a Unicode string as input and returns that string with any precomposed
characters decomposed into their separate elements. This is the opposite of COMPOSE.
For example, DECOMPOSE(‘ã’) yields ‘a˜’. (See COMPOSE.)

GREATEST(string1, string2, ...)

Takes one or more strings as input, and returns the string that would come last (i.e.,
that is the greatest) if the inputs were sorted in ascending order. Also see the LEAST
function, which is the opposite of GREATEST.

INITCAP(string1)

Reformats the case of the string argument, setting the first letter of each word to
uppercase and the remainder of the letters to lowercase. This is sometimes called
title case. A word is a set of characters separated by a space or nonalphanumeric
character (such as # or _). For example, INITCAP(‘this is lower’) gives ‘This Is
Lower’.

INSTR(string1, string2)

Returns the position at which string2 is found within string1; if it is not found,
returns 0.

Several variations are available:
INSTR(string1, string2, start_position)
Begins searching for string2 at the column in string1 indicated by start_position.
The default start position is 1, so INSTR(string1, string2, 1) is equivalent
to INSTR(string1, string2).
INSTR(string1, string2, negative_start_position)
Begins searching from the end of string1 rather than from the beginning.
INSTR(string1, string2, start_position, nth)
Finds the nth occurrence of string2 after the start_position.
INSTR(string1, string2, negative_start_position, nth)
Finds the nth occurrence of string2, counting from the end of string1.

LEAST(string1, string2, ...)

Takes one or more strings as input and returns the string that would come first (i.e.,
that is the least) if the inputs were sorted in ascending order.

LENGTH(string1)

LOWER(string1)

LPAD(string1, padded_length)

LTRIM(string1)

NCHR(code_location)

NLS_INITCAP(string1)

NLS_LOWER(string1) and NLS_LOWER(string1, ‘NLS_SORT=sort_se
quence_name’)

NLS_UPPER(string1) and NLS_UPPER(string1, ‘NLS_SORT=sort_se
quence_name’)

SUBSTR(string1, start, length)

上一篇下一篇

猜你喜欢

热点阅读