PLSQL
PLSQL
IN =ANY = SOME
IS EMPTY PARA VARRAY O TABLE
IS A SET PARA VARRAY O TABLE
MEMBER OF SOLO PARA COLECCIONES ESCALARES
VARIABLES
INSERT ALL
WHEN CONDICION THEN
INTO TABLA (CAMPOS) VALUES (VALORES)
WHEN CONDICION THEN
INTO TABLA (CAMPOS) VALUES (VALORES)
ELSE
INTO TABLA (CAMPOS) VALUES (VALORES)
SELECT * FROM DUAL;
SQL
INNER JOIN
SELECT suppliers.supplier_id, suppliers.supplier_name, orders.order_date
FROM suppliers
INNER JOIN orders -- REGISTROS DE LA PRIMERA Q ESTEN EN LA SEGUNDA
ON suppliers.supplier_id = orders.supplier_id;
PIVOT
SELECT * FROM
(
SELECT customer_ref, product_id
FROM orders
)
PIVOT
(
COUNT(product_id) - siempre una funcion de agrupacion.
FOR product_id IN (10, 20, 30) para estos productos
)
ORDER BY customer_ref;
LIKE
SELECT *
FROM jobs WHERE job_id LIKE 'SA\_%' ESCAPE '\'; (EL GUION BAJO REEMPLAZA UN CARACTER)
count(*) over(partition by otro order by algo rows range between unbounded/1/2 preceding
and current row/ current and following rows) from varios a
DATA TYPE COMPUESTAS
SQL UDT
A SQL UDT is an object type. Like packages, object types have a specification and a body. The
specification is the type and includes a list of attributes (or fields) and methods. COMO EN C, JAVA
Collections are arrays and lists. Arrays differ from lists in that they use a sequentially
numbered index, while lists use a nonsequential numeric or unique string index. Arrays are
densely populated lists because they have sequentially numbered indexes. While lists can
have densely populated numeric indexes, they can also be sparsely populated, meaning there
are gaps in a sequence or the indexes are not sequential.
Oracle supports three types of collections. Two are both SQL and PL/SQL data types,
depending on how you define them: varray and nested table (or table). The third collection
type is a PL/SQL-only data type, called an associative array. The associative array is also
known as a PL/SQL table or an index-by table.
collection may be a varray or nested table (Oracle uses the term nested table to
disambiguate the difference between a programming data type and a physical table) of
a scalar or composite data type. A collection of a scalar data type is an Attribute Data
Type (ADT), as qualified in Chapter 3, while a collection of a composite data type is a
user-defined type (UDT). Collections may use an object data type in a SQL context and a
record data type in a PL/SQL context.
An associative array (formerly called PL/SQL table or index-by table) is a set of key-value pairs.
Each key is a unique index, used to locate the associated value with the
syntax variable_name(index).
2 columnas
DECLARE
BEGIN
-- Add elements (key-value pairs) to associative array:
city_population('Smallville') := 2000;
city_population('Midland') := 750000;
city_population('Megalopolis') := 1000000;
-- Change value associated with key 'Smallville':
city_population('Smallville') := 2001;
-- Print associative array:
i := city_population.FIRST; -- Get first element of array
WHILE i IS NOT NULL LOOP
DBMS_Output.PUT_LINE
('Population of ' || i || ' is ' || city_population(i));
i := city_population.NEXT(i); -- Get next element of array
END LOOP;
END;
DECLARE
TYPE sum_multiples IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
n PLS_INTEGER := 5; -- number of multiples to sum for display
sn PLS_INTEGER := 10; -- number of multiples to sum
m PLS_INTEGER := 3; -- multiple
FUNCTION get_sum_multiples ( multiple IN PLS_INTEGER, num IN PLS_INTEGER ) RETURN sum_multiples IS
s sum_multiples;
BEGIN
FOR i IN 1..num LOOP
s(i) := multiple * ((i * (i + 1)) / 2); -- sum of multiples
END LOOP;
RETURN s;
END get_sum_multiples;
A varray (variable-size array) is an array whose number of elements can vary from zero (empty) to
the declared maximum size.
a nested table is a column type that stores an unspecified number of rows in no particular order.
TYPE Roster IS TABLE OF VARCHAR2(15); -- nested table type
names Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');
Anidados:
DECLARE
TYPE tb1 IS TABLE OF VARCHAR2(20); -- nested table of strings
vtb1 tb1 := tb1('one', 'three');
BEGIN
vntb1.EXTEND;
vntb1(2) := vntb1(1);
vntb1.DELETE(1); -- delete first element of vntb1
vntb1(2).DELETE(1); -- delete first string from second table in nested table
END;
VARIABLE: REF cursor, no atado a una query especifica y puede pasarse entre programas
c_direct_reports SYS_REFCURSOR;
BEGIN
OPEN c_direct_reports FOR SELECT employee_id, etc FROM employees
WHERE algo;
RETURN c_direct_reports;
END;
ATRIBUTOS
%FOUND Returns TRUE only when a DML statement has changed a row.
%ISOPEN Always returns FALSE for any implicit cursor.
%NOTFOUND Returns TRUE when a DML statement fails to change a row.
%ROWCOUNT Returns the number of rows changed by a DML statement or the number
DECLARE
lv_id item.item_id%TYPE;
lv_title VARCHAR2(60);
CURSOR c IS
SELECT item_id , item_title FROM item;
BEGIN
OPEN c;
LOOP
FETCH c INTO lv_id , lv_title;
EXIT WHEN c%NOTFOUND;
dbms_output.put_line('Title ['||lv_title||']');
END LOOP;
CLOSE c;
END;
PACKAGES
DBMS_SQL para SQL Dyn. Sino usamos SQL nativo (EXECUTE IMMEDIATE) o ambos.
DBMS_SQL.DEFINE_COLUMN (cursor,posicion,tipo)
DEFINE_COLUMN_LONG(cursor,posicion)
DEFINE_ARRAY( cursor,posicion,tipo): definen variables como un select into
el array es la coleccion de las columnas en las que queremos meter las filas ,traidas con FETCH_ROWS).
Cuando hacemos fetch las filas se copian a buffer hasta que hacemos COLUMN_VALUE, ahi se copian a
la tabla que se paso como argumento de COLUMN_VALUE.
DBMS_SQL.EXECUTE(cursor) / DBMS_SQL.EXECUTE_AND_FETCH
DBMS_SQL.FETCH_ROWS(cursor)
EJEMPLOS
BEGIN
source_cursor := dbms_sql.open_cursor;
DBMS_SQL.PARSE(source_cursor,
'SELECT id, name, birthdate FROM ' || source,
DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(source_cursor, 1, id_var);
DBMS_SQL.DEFINE_COLUMN(source_cursor, 2, name_var, 30);
DBMS_SQL.DEFINE_COLUMN(source_cursor, 3, birthdate_var);
ignore := DBMS_SQL.EXECUTE(source_cursor);
destination_cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(destination_cursor,
'INSERT INTO ' || destination ||
' VALUES (:id_bind, :name_bind, :birthdate_bind)',
DBMS_SQL.NATIVE);
LOOP
IF DBMS_SQL.FETCH_ROWS(source_cursor)>0 THEN
-- get column values of the row
DBMS_SQL.COLUMN_VALUE(source_cursor, 1, id_var);
DBMS_SQL.COLUMN_VALUE(source_cursor, 2, name_var);
DBMS_SQL.COLUMN_VALUE(source_cursor, 3, birthdate_var);
-- Bind the row into the cursor that inserts into the destination table.
DBMS_SQL.BIND_VARIABLE(destination_cursor, ':id_bind', id_var);
DBMS_SQL.BIND_VARIABLE(destination_cursor, ':name_bind', name_var);
DBMS_SQL.BIND_VARIABLE(destination_cursor, ':birthdate_bind',
birthdate_var);
ignore := DBMS_SQL.EXECUTE(destination_cursor);
ELSE
EXIT;
END IF;
END LOOP;
COMMIT;
DBMS_SQL.CLOSE_CURSOR(source_cursor);
DBMS_SQL.CLOSE_CURSOR(destination_cursor);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(source_cursor) THEN
DBMS_SQL.CLOSE_CURSOR(source_cursor);
END IF;
IF DBMS_SQL.IS_OPEN(destination_cursor) THEN
DBMS_SQL.CLOSE_CURSOR(destination_cursor);
END IF;
RAISE;
END;
/
Example 4: RETURNING clause
With this clause, INSERT, UPDATE, and DELETE statements can return values of expressions in bind
variables.
If a single row is inserted, updated, or deleted, then use DBMS_SQL.BIND_VARIABLE to bind these
outbinds. To get the values in these bind variables, call DBMS_SQL.VARIABLE_VALUE
Note:This process is similar to DBMS_SQL.VARIABLE_VALUE, which must be called after running a PL/SQL
block with an outbind inside DBMS_SQL.
i) Single-row insert
DBMS_SQL.CLOSE_CURSOR (cur);
END;
/
Now I can execute this "update by array" procedure for the sal column of the emp table.
DECLARE
emps DBMS_SQL.NUMBER_TABLE;
sals DBMS_SQL.NUMBER_TABLE;
BEGIN
emps (1) := 7499;
sals (1) := 2000;
emps (2) := 7521;
sals (2) := 3000;
DECLARE
l_sql VARCHAR2(100);
l_ename emp.ename%TYPE;
BEGIN
l_sql := 'SELECT ename FROM emp WHERE empno = :empno';
EXECUTE IMMEDIATE l_sql INTO l_ename USING 1234;
END;
/
Dynamic Cursors
Sometimes the definition of the cursor may not be known until runtime. The following example shows
this along with access of an object that it not currently present. It should compile in any schema as
there are no direct references to database objects until runtime.
CREATE OR REPLACE
PROCEDURE DynamicCursor (p_parameter IN VARCHAR2) IS
TYPE cur_typ IS REF CURSOR;
c_cursor cur_typ;
l_query VARCHAR2(1000);
l_text VARCHAR2(100);
BEGIN
UTL_FILE
Subprogram Description
FGETPOS Function Returns the current relative offset position within a file, in bytes
FREMOVE Procedure Deletes a disk file, assuming that you have sufficient privileges
UTL_FILE.FREMOVE ( location IN VARCHAR2, filename IN VARCHAR2);
FSEEK Procedure Adjusts the file pointer forward or backward within the file by the
number of bytes specified
GET_RAW Function Reads a RAW string value from a file and adjusts the file pointer
ahead by the number of bytes read
PUTF Procedure A PUT procedure with formatting, puede venir con \n and %s
UTL_FILE.PUTF (
file IN UTL_FILE.FILE_TYPE,
format IN VARCHAR2,
[arg1 IN VARCHAR2 DEFAULT NULL,
...
arg5 IN VARCHAR2 DEFAULT NULL]);
PUT_RAW Function Accepts as input a RAW data value and writes the value to the
output buffer
F1 := UTL_FILE.FOPEN('UTL_FILE_TEMP','u12345.tmp','R');
UTL_FILE.GET_LINE(F1,V1);
DBMS_OUTPUT.PUT_LINE('Get line: ' || V1);
UTL_FILE.FCLOSE(F1);
declare
handle utl_file.file_type;
my_world varchar2(4) := 'Zork';
begin
handle := utl_file.fopen('UTL_FILE_TEMP','u12345.tmp','a');
utl_file.putf(handle, '\nHello, world!\nI come from %s with %s.\n', my_world,
'greetings for all earthlings');
utl_file.fflush(handle);
utl_file.fclose(handle);
end;
JSON
DECLARE
je JSON_ELEMENT_T;
jo JSON_OBJECT_T;
BEGIN
je := JSON_ELEMENT_T.parse('{"name":"Radio controlled plane"}');
IF (je.is_Object) THEN
jo := treat(je AS JSON_OBJECT_T);
jo.put('price', 149.99);
END IF;
DBMS_OUTPUT.put_line(je.to_string);
END;
DECLARE
jo JSON_OBJECT_T;
ja JSON_ARRAY_T;
keys JSON_KEY_LIST;
keys_string VARCHAR2(100);
BEGIN
ja := new JSON_ARRAY_T;
jo := JSON_OBJECT_T.parse('{"name":"Beda",
"jobTitle":"codmonki",
"projects":["json", "xml"]}');
keys := jo.get_keys;
FOR i IN 1..keys.COUNT LOOP
ja.append(keys(i));
END LOOP;
keys_string := ja.to_string;
DBMS_OUTPUT.put_line(keys_string);
END;
/
You can use BULK COLLECT in all these forms:
DECLARE
TYPE employee_info_t IS TABLE OF employees%ROWTYPE;
l_employees employee_info_t;
BEGIN
SELECT *
BULK COLLECT INTO l_employees
FROM employees
WHERE department_id = 50;
DBMS_OUTPUT.PUT_LINE (l_employees.COUNT);
END;
If you do not want to retrieve all the columns in a table, create your own user-defined record type and
use that to define your collection. All you have to do is make sure the list of expressions in the SELECT
match the record type's fields.
DECLARE
TYPE two_cols_rt IS RECORD (
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
l_employees employee_info_t;
BEGIN
SELECT employee_id, salary
BULK COLLECT INTO l_employees
FROM employees
WHERE department_id = 50;
DBMS_OUTPUT.PUT_LINE (l_employees.COUNT);
END;
Quick Tip
You can avoid the nuisance of declaring a record type to serve as the type for the collection through the
use of a "template cursor." This cursor should have the same select list as the BULK COLLECT query. You
can, however, leave off the WHERE clause and anything else after the FROM clause, because it will
never be used for anything but a %ROWTYPE declaration. Here's an example:
DECLARE
CURSOR employee_info_c IS
SELECT employee_id, salary
FROM employees ;
l_employees employee_info_t;
BEGIN
SELECT employee_id, salary
BULK COLLECT INTO l_employees
FROM employees
WHERE department_id = 10;
END;
BEGIN
OPEN cur;
LOOP
FETCH cur BULK COLLECT
INTO m_rowid, m_col1, m_col2 LIMIT contador;
FOR i IN 1 .. m_rowid.count
LOOP
m_col1(i) := calculos(m_col1(i), m_col2(i));
END LOOP;
FORALL i IN 1 .. m_rowid.count
UPDATE tabla_enorme
SET col1 = m_col1(i)
WHERE rowid = m_rowid(i);
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
END;
Un cambio que puede mejorar el rendimiento aún mas, es que que en el FORALL, sustituir el
m_rowid.count, por m_rowid.last.
DECLARE
type clientes_array is table of XXX%rowtype index by binary_integer;
registros clientes_array;
errores NUMBER;
dml_errores EXCEPTION;
contador_errores number := 0;
PRAGMA exception_init(dml_errores, -24381);
cursor c is select * from XXX;
BEGIN
open c;
loop
fetch c BULK COLLECT INTO registros LIMIT 1000;
begin
FORALL i IN 1 .. registros.count SAVE EXCEPTIONS
insert into TRASPASO_BD_CLIENTE values registros(i);
EXCEPTION
WHEN dml_errores THEN
errores := SQL%BULK_EXCEPTIONS.COUNT;
contador_errores := contador_errores + errores;
FOR i IN 1..errores LOOP
dbms_output.put_line
(‘Se encontro el error ‘||;SQL%BULK_EXCEPTIONS(i).ERROR_INDEX ||
‘:’||SQL%BULK_EXCEPTIONS(i).ERROR_CODE);
end loop;
end;
exit when c%notfound;
END LOOP;
close c;
dbms_output.put_line( contador_errores );
end;
NOVEDADES EN 12
SELECT i.item_title
2 FROM FABLE i WHERE XXXXX ORDER BY XXXXX
3 (OFFSET 20 ROWS ) / FETCH FIRST/NEXT N ROWS ONLY / FETCH FIRST 20 PERCENT ROWS
ONLY / WITH TIES, ONLY trae los N registros sean sus valores del order by iualrd o no. WITH TIES tae todos los
empatados tambien