Oracle’da Tablo Fonksiyonları (Table Functions)

6 Aralık 2008

Oracle

Microsoft SQL Server, “Tablo Fonksiyonları” yazarken programcıya büyük esneklik ve kolaylık sağlıyor. Tablo fonksiyonları (Table Functions), tablo (dizi) döndüren fonksiyonların genel adıdır. Bunun daha iyi anlaşılması için şu T-SQL örneğine bir göz atalım. T-SQL örneği olmasına rağmen, aslında örnek Oracle ile uğraşanların yakından tanıdığı HR scheması ile ilgili:

CREATE FUNCTION Employees_List
(@dept_id INT )
RETURNS TABLE
AS
RETURN
SELECT employee_id, first_name, last_name
FROM employees
WHERE department_id = @dept_id
GO

Bu fonksiyon bir SELECT içinde çağrılıp, sanki bir tabloymuş gibi görev yapabilir. Anlaşılacağı üzere departmen_id kolonuna göre EMPLOYEES tablosunda filtreleme yapıp, kayıtları bir tablo olarak döndürmektedir. Örnek:

SELECT * FROM Employees_List( 50 );

Konuyla ilgili çok daha detaylı ve kompleks örnekler verilebilir ama benim amacım T-SQL öğretmek değil, sadece benzer yapının Oracle’da nasıl yazıldığını ve aradaki farkları karşılaştırmak istiyorum.

T-SQL’de yazılmış halini verdiğimiz fonksiyonu Oracle’da PL/SQL ile yazmak istediğimizde önümüze hemen bir engel çıkıyor. PL/SQL’de fonksiyonları tanımlarken belirsiz bir tip olarak TABLE döndürür diyemiyoruz. Fonksiyonun belirli bir tip döndürmesi gerekiyor, NUMBER, VARCHAR2 gibi varolan tipler işimizi görmeyeceğinden biz öncelikle bir OBJECT tanımlıyoruz:

CREATE OR REPLACE TYPE emp_sonuc_satir as OBJECT(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(25));

Şimdi de elemanları bu objelerden oluşan bir tablo tipi yaratmamız gerekiyor:

CREATE OR REPLACE TYPE emp_sonuc_tablo AS TABLE OF emp_sonuc_satir;

Artık fonksiyonumuzu yazabiliriz:

CREATE OR REPLACE FUNCTION employees_list (dept_id NUMBER)
RETURN emp_sonuc_tablo
IS
sonuc   emp_sonuc_tablo := NEW emp_sonuc_tablo();
BEGIN
FOR satir IN (SELECT employee_id,
first_name,
last_name
FROM employees
WHERE department_id = dept_id) LOOP
SONUC.EXTEND;
SONUC(SONUC.COUNT) := new emp_sonuc_satir( satir.employee_id, satir.first_name, satir.last_name);
END LOOP;
RETURN sonuc;
END;

Bu oluşturduğumuz fonksiyonu SELECT ile beraber şu şekilde kullanabiliriz:

SELECT * FROM TABLE( employees_list( 50 ));

Görüldüğü üzere benzer fonksiyonu T-SQL yazmak kesinlikle daha kolay. Fonksiyonun döndürdüğü tablonun yapısında değişiklik yapmak isterseniz sadece fonksiyonun içeriğini değil, ilgili TYPE’ları da değiştirmeniz gerekiyor.

Buna karşın Oracle’ın tablo fonksiyonlarının SQL Server’a göre bir üstünlüğü var. PIPELINED parametresi ile yaratılan fonksiyonlar, dönen tablo değerlerinin toplu değil satır satır dönmesini sağlıyor. Yukardaki fonksiyonu PIPELINED yazmak için:

CREATE OR REPLACE FUNCTION employees_list_piped (dept_id NUMBER)
RETURN emp_sonuc_tablo PIPELINED
IS
sonuc emp_sonuc_satir := new emp_sonuc_satir(null, null, null);
BEGIN
FOR satir IN (SELECT employee_id,
first_name,
last_name
FROM employees
WHERE department_id = dept_id) LOOP
sonuc.employee_id := satir.employee_id;
sonuc.first_name := satir.first_name;
sonuc.last_name := satir.last_name;
PIPE ROW(sonuc);
END LOOP;
RETURN;
END;

Bu yeni fonksiyonu da bir önceki gibi çağırabiliyoruz:

SELECT * FROM TABLE( employees_list_piped( 50 ));

Oracle’ın sağladığı PIPELINE, tablo fonksiyonlarının performans problemini azaltan bir özellik olarak ortaya çıkıyor. Buna karşın SQL Server, esnek ve basit fonksiyon yazımı sayesinde programcıların işini kolaylaştırıyor.

Bookmark and Share
,

Yazar:

Gökhan Atıl <gokhan@gokhanatil.com>

Veritabanı ve Unix uzmanı olarak Koç.Net'de çalışmaktadır. OCP (Oracle Certified Professional), Oracle Certified SQL Expert, Comptia Linux+ sertifikalarına sahiptir.

6 Responses to “Oracle’da Tablo Fonksiyonları (Table Functions)”

  1. Murat:

    Hocam merhaba, Oracle içerisinde benzer isimli tabloları, .nette bir comboboxa atamayı gerçekleştirmem lazım.

    select * from dba_objects where object_name like ‘DB%’;

    şeklinde bir komut işimi görmüyor. Ne yapabilirim?

  2. Gökhan Atıl:

    Murat, benzer isimli tabloları almak için dba_objects yerine dba_tables tablosunu sorgulaman çok daha iyi olur:

    SELECT * FROM dba_tables WHERE table_name LIKE ‘DB%’;

    Bu sorguyu yapabilmek için, veritabanına bağlandığın kullanıcının dba_tables tablosuna erişebilmesi gerekir. Bunun için kullanıcına dba_tables tablosuna SELECT yetkisi verebilirsin:

    GRANT SELECT ON dba_tables TO kullanici_adi;

  3. Gökhan:

    Merhaba aşağıdaki kodu çalıştırmaya çalışıyorum.(@c_X double .. burada hata veriyor.sorun ne olabilir bulamadım yardımcı olursanız sevinirim.

    DELIMITER $$
    DROP FUNCTION IF EXISTS `f1`.`Get_Coordinate_From_Subscriber` $$
    CREATE FUNCTION `f1`.`Get_Coordinate_From_Subscriber` (@c_x double,@c_y double)
    returns @outgoings table
    (
    msisdn text,
    blood_type text,
    coord_x_fp double,
    coord_y_fp double
    )
    as
    begin
    ..
    .

  4. Gökhan Atıl:

    SQL Server uzmanı değilim ama sanırım sorun “Double” veri tipinde. Double yerine float(24/53) veya real değişken tipini kullanmanız gerekiyor.

  5. Ramazan Aktı:

    Bu fonksiyonu asp kodları arasında kullanabilirmiyim? oraclede kullandım table foksiyonunu ama ASP de yapamadım. ASP.NET değil Asp olduğunu belirtmek istiyorum tekrardan.

  6. Gökhan Atıl:

    Ramazan, ASP’nin yetenekleri konusunda bilgi sahibi olmadığımdan buna net bir cevap vemem mümkün değil.


Leave a Reply