PostgreSQL / PostgreSQL функц бичих

PostgreSQL функц бичих

Та нэг давтагдах тооцоог олон газар бичиж байна уу? PostgreSQL-д өөрийн функц бичиж, SQL асуулгаас дуудаж болно. Хөгжүүлэгчид ихэвчлэн нарийн бизнесийн логикийг функцэд оруулж, application layer-аас хамгаалдаг. Энэ хичээлд PL/pgSQL — PostgreSQL-н хамгийн нийтлэг функцийн хэл — сурна.

Энгийн SQL функц

Параметр авч нэг утга буцаадаг хамгийн энгийн функц:

sql
-- Нэр ба овгийг нийлүүлэх функц
CREATE OR REPLACE FUNCTION full_name(first_name TEXT, last_name TEXT)
RETURNS TEXT
LANGUAGE SQL
AS $$
    SELECT first_name || ' ' || last_name;
$$;

-- Дуудах
SELECT full_name('Болд', 'Баатар');
-- Үр дүн: Болд Баатар

-- Хүснэгтийн баганатай хамт ашиглах
SELECT full_name(first_name, last_name) AS бүтэн_нэр, email
FROM users;

$$ тэмдэглэгээ нь функцийн биеийг хязгаарладаг. CREATE OR REPLACE нь функц байгаа бол шинэчилж, байхгүй бол шинээр үүсгэнэ.

PL/pgSQL функц — нарийн логик

PL/pgSQL нь нөхцөл шалгалт, давталт, хувьсагч зэрэг боломж агуулсан процедур хэл юм:

sql
-- XP-с level тооцоолох функц
CREATE OR REPLACE FUNCTION get_level(xp INT)
RETURNS INT
LANGUAGE plpgsql
AS $$
DECLARE
    level INT;
BEGIN
    IF xp < 100 THEN
        level := 1;
    ELSIF xp < 500 THEN
        level := 2;
    ELSIF xp < 1500 THEN
        level := 3;
    ELSIF xp < 4000 THEN
        level := 4;
    ELSE
        level := 5;
    END IF;

    RETURN level;
END;
$$;

-- Дуудах
SELECT get_level(250);   -- Үр дүн: 2
SELECT get_level(2000);  -- Үр дүн: 4

DECLARE хэсэгт хувьсагч зарлана. BEGIN ... END хооронд логик бичнэ. RETURN үр дүн буцаана.

Хүснэгт буцаадаг функц (RETURNS TABLE)

Функц зөвхөн нэг утга биш, бүх хүснэгт буцааж болно:

sql
-- Хэлтсийн ажилчдыг буцаадаг функц
CREATE OR REPLACE FUNCTION get_employees_by_dept(dept_name TEXT)
RETURNS TABLE(
    нэр         TEXT,
    имэйл       TEXT,
    цалин       NUMERIC,
    ажилласан_жил INT
)
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN QUERY
    SELECT
        e.full_name,
        e.email,
        e.salary,
        DATE_PART('year', AGE(NOW(), e.hired_at))::INT
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    WHERE d.name = dept_name
    ORDER BY e.salary DESC;
END;
$$;

-- Хүснэгт шиг дуудах
SELECT * FROM get_employees_by_dept('Инженер');

-- WHERE нэмж болно
SELECT нэр, цалин
FROM get_employees_by_dept('Инженер')
WHERE цалин > 2000000;

DEFAULT параметр ба алдаа шидэх

sql
-- Хуучин захиалгыг архивлах функц
CREATE OR REPLACE FUNCTION archive_old_orders(days_old INT DEFAULT 365)
RETURNS INT
LANGUAGE plpgsql
AS $$
DECLARE
    moved_count INT;
BEGIN
    -- days_old сөрөг байвал алдаа шид
    IF days_old <= 0 THEN
        RAISE EXCEPTION 'days_old must be positive, got: %', days_old;
    END IF;

    -- Хуучин захиалгыг тоол
    SELECT COUNT(*) INTO moved_count
    FROM orders
    WHERE created_at < NOW() - (days_old || ' days')::INTERVAL
      AND status = 'completed';

    -- Тоог буцаах (жишээ — бодит архивлалт хийхгүй)
    RETURN moved_count;
END;
$$;

-- Default параметртэй дуудах (365 хоногоос хуучин)
SELECT archive_old_orders();

-- Тусгай утгаар дуудах
SELECT archive_old_orders(90);

Функц устгах

sql
-- Нэр болон параметрийн төрлийг зааж устгана
DROP FUNCTION get_level(INT);

DROP FUNCTION IF EXISTS get_employees_by_dept(TEXT);

Нэг нэртэй олон функц өөр параметртэй байж болох учраас (overloading) устгахдаа параметрийн төрлийг заах шаардлагатай.

Дараагийн хичээлд:

Хүснэгтэд INSERT, UPDATE, DELETE үйлдэл болох үед автоматаар ажилладаг trigger функцийг бичиж сурна.