2010-02-25 8 views
6

Bunun temel bir şey gibi göründüğünü biliyorum ama bunu daha önce hiç yapmadım.Oracle PL/SQL işlevinden varolan bir tablodan kayıt nasıl geri alınır?

Oracle PL/SQL işlevinin sonucu olarak varolan bir tablodan tek bir kayıt döndürmek istiyorum. Bunu zaten yapmanın birkaç farklı yolunu buldum, ancak en iyi yolunu kullanmakla ilgileniyorum (okuduğum şeyle mutlu değilim).

Yaptığım şeyin özü şudur: 'Kullanıcılar' adlı bir tablom var ve bir KullanıcıAdı verilen (söz konusu kullanıcı hakkındaki diğer güvenilir bilgilerin yanı sıra) bir 'update_and_get_user' işlevini istiyorum. 'Kullanıcılar' tablosunda çeşitli eylemler gerçekleştirin ve ardından söz konusu tablodan sıfır veya bir satır/kayıt döndürün.

Bu anda kafamda kod temel taslak olduğunu (okuyun: hiçbir fikri sözdizimi düzeltmek için bile yakın olup olmadığını):

CREATE FUNCTION update_and_get_user(UserName in VARCHAR2, OtherStuff in VARCHAR2) 
    RETURN users PIPELINED IS 
    TYPE ref0 IS REF CURSOR; 
    cur0  ref0; 
    output_rec users%ROWTYPE; 
BEGIN 
    -- Do stuff 

    -- Return the row (or nothing) 
    OPEN cur0 FOR 'SELECT * FROM users WHERE username = :1' 
    USING UserName; 

    LOOP 
    FETCH cur0 INTO output_rec; 
    EXIT WHEN cur0%NOTFOUND; 
    PIPE ROW(output_rec); 
    END LOOP; 
END update_and_get_user; 

rekor veya masa nerede olduğunu örnek gördüm döndü, önceden oluşturulmuş/bildirilen kayıt veya tablo türü, ancak tablo zaten tanımlanmış gibi görünüyor, bunu kullanabilmem gerekir ve bu nedenle tablo değişiklikleri durumunda tür bildirim kodu eşitleme hakkında endişelenmenize gerek yok hiç yapılmadı. veritabanı birden çok kez iletişim başka dil/çerçevede kod aksine (tek bir PL/SQL işlevinde bu tutmak istiyorum

Ben tüm potansiyel çözümler ve yorumların açığım, ama gerçektendo , işlev çağrıldığında sistem olarak veritabanının kendisi farklı şehirler olabileceğinden, 'SELECT * FROM kullanıcı adı WHERE kullanıcı adı = blah') ile sonlanır. Bu sınırın dışında, düşüncemi değiştirmeye açığım.

cevap

12

Bunu nasıl yapacağım. Değişkenler/tablo adları/sütun adları Oracle'da büyük/küçük harf duyarlıdır, bu yüzden UserName yerine user_name kullanırdım.

CREATE TABLE users(UserName varchar2(20), OtherStuff VARCHAR2(20)); 

Fonksiyon update_and_get_user. Pipelined Tables yerine ROWTYPE döndürdüğümü unutmayın.

Ve nasıl böyle adlandırırsınız. ROWTYPE'un NULL olmasını kontrol edemezsiniz, ancak örneğin username'u kontrol edebilirsiniz.

DECLARE 
    users_rec users%ROWTYPE; 
BEGIN 
    users_rec := update_and_get_user('user', 'stuff'); 
    IF(users_rec.username IS NOT NULL) THEN 
    dbms_output.put_line('FOUND: ' || users_rec.otherstuff); 
    END IF; 
END; 

PIPED ROWS kullanan bir çözüm aşağıda, ama bu şekilde çalışmıyor. Sorgu içindeki tabloları güncelleyemezsiniz.

SELECT * FROM TABLE(update_and_get_user('user', 'stuff')) 

ORA-14551: cannot perform a DML operation inside a query 

Çözüm bu şekilde görünecektir:

CREATE OR REPLACE TYPE users_type 
AS OBJECT 
(
    username VARCHAR2(20), 
    otherstuff VARCHAR2(20) 
) 

CREATE OR REPLACE TYPE users_tab 
    AS TABLE OF users_type; 

CREATE OR REPLACE FUNCTION update_and_get_user(
    in_UserName IN users.username%TYPE, 
    in_OtherStuff IN users.otherstuff%TYPE) 
RETURN users_tab PIPELINED 
IS 
    output_rec users%ROWTYPE; 
BEGIN 
    UPDATE users 
    SET OtherStuff = in_OtherStuff 
    WHERE UserName = in_UserName 
    RETURNING username, otherstuff 
    INTO output_rec; 
    PIPE ROW(users_type(output_rec.username, output_rec.otherstuff)); 
END; 
+0

1 Kapsamlı cevap Peter - Sen (benim yazarak hızlandırmak gerekir) beni alt ihtiyaç Paul durumunda , bu bağlantı (http : //download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/rowtype_attribute.htm#LNPLS01342)% rowtype niteliğini açıklıyor –

+1

+1 Peter! Keşke birden fazla oy verebilseydim. İlk olarak, bu gerçekten iyi görünüyor. İkincisi, UPDATE'de "GERİ DÖNÜŞÜM ... INTO ..." yapabileceğinizden hiçbir fikrim yoktu, bu gerçekten harika ve performansı artıracak.Üçüncüsü, bir tablo fonksiyonunun bir sorgusu içinde bir güncelleme yapamayacağımı hiç bilmiyordum, ki bu da beni büyük ölçüde hayal kırıklığına uğratırdı. Bunu uyguladıktan/onayladıktan sonra bunu kabul edilen cevap olarak işaretleyeceğim. Teşekkür ederim! –

+0

Peki, iyi şanslar :) –

İlgili konular