الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

كيفية إسترجاع غرض من نوع جدول

مغلق
بدأه MMA_EG_Cairo في 7 يوليو 2007 · 10 رد · 3,415 مشاهدة · في قسم لغةالاجرائات Pl/sql
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

إخواني الكرام ، يمكنني إجراء Function داخل SQL-Server ، تقوم بإرجاع جدول كما يلي :

Create Function List_Emp(@ID_Start	BigInt,@ID_End BigInt) Return Table
As
  Return   Select * Fom Emp Where Emp_ID Between @ID_Start And @ID_End
Go

ولكي يتم إستخدام هذا الغرض ، يمكن من خلال الكود التالي :

Select * From dbo.List_Emp(10,20)

سؤالي هنا : هل يمكن إجراء مثل هذه العملية من داخل الأوراكل ؟ فإذا كانت الإجابة بنعم فما هي الطريقة ؟ وإذا كانت الإجابة بلا ، فهل هناك بديل لهذه المشكلة ؟

وشكراً

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#2

هل موضوعي صعب

رجاء المساعدة

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#3

نعم ممكن لاحظ المثال :

الجداول :

CREATE TABLE month_costs (
  Cost_no Number(4),
  Quantity Number(3),
  Type Char(1),
  Amount Number(7,2)
);

CREATE TABLE month_sub_costs (
  Cost_no Number(4),
  Sub_cost_no Number(4),
  Quantity Number(3),
  Type Char(1),
  Amount Number(7,2)
);

CREATE TABLE ytd_costs (
  Cost_no Number(4),
  Quantity Number(3),
  Type Char(1),
  Amount Number(7,2),
  status char(1)
);

إنشاء Package كالتالي :

CREATE PACKAGE ref_pkg IS
  TYPE refcur_t IS REF CURSOR RETURN month_costs%ROWTYPE;
  TYPE dst_ytd_lines IS TABLE OF ytd_costs%ROWTYPE;
END ref_pkg;
/

إنشاء الدالة :

CREATE OR REPLACE FUNCTION generate_lines (cur_month_lines_ref
	   IN ref_pkg.refcur_t)
RETURN ref_pkg.dst_ytd_lines pipelined
  IS
  r_month_costs	   month_costs%ROWTYPE;
  r_ytd_costs		 ytd_costs%ROWTYPE;

  TYPE dst_subcosts IS TABLE OF month_sub_costs%ROWTYPE;
  tab_subcosts	  dst_subcosts := dst_subcosts();
  tab_subcosts_null dst_subcosts := dst_subcosts();
  -- For re-initialization

  CURSOR c_subtot (b_costno month_sub_costs.cost_no%TYPE)
  IS SELECT * FROM month_sub_costs WHERE cost_no = b_costno;

  t_is_data					 BOOLEAN;
  t_diff_type				   BOOLEAN;
  i_index					   PLS_INTEGER;
  -- save_amount				   month_costs.amount%TYPE;

-- PL/SQL Block
BEGIN
  LOOP
	FETCH cur_month_lines_ref INTO r_month_costs;
	EXIT WHEN cur_month_lines_ref%NOTFOUND;

	-- Get data directly to be carried over from month_costs
	   to ytd_costs here
	r_ytd_costs.cost_no		 := r_month_costs.cost_no;
	r_ytd_costs.quantity		:= r_month_costs.quantity;
	r_ytd_costs.type			:= r_month_costs.type;
	r_ytd_costs.amount		  := r_month_costs.amount;

	-- Initializations
	tab_subcosts		:= tab_subcosts_null;
	t_is_data		   := FALSE;
	t_diff_type		 := FALSE;
	i_index			 := 0;

	FOR r_subtot IN c_subtot( r_month_costs.cost_no)
	LOOP
	  t_is_data			   := TRUE;
	  tab_subcosts.EXTEND;
	  i_index := tab_subcosts.LAST;

	  tab_subcosts(i_index).quantity  := r_subtot.quantity;
	  tab_subcosts(i_index).type	  := r_subtot.type;
	  tab_subcosts(i_index).amount	:= r_subtot.amount;

	  IF (((i_index - 1) > 0) AND ( tab_subcosts(i_index).type
		 <> tab_subcosts(i_index - 1).type ))THEN
		t_diff_type	:= TRUE;
	  END IF;
	END LOOP;

	i_index := 0;

	IF ( t_is_data = FALSE ) THEN
	  PIPE ROW(r_ytd_costs);
	ELSE
	  r_ytd_costs.quantity	  := 0;
	  r_ytd_costs.type		  := NULL;
	  r_ytd_costs.amount		:= 0;

	  FOR i_index IN tab_subcosts.FIRST .. tab_subcosts.LAST
	  LOOP
		r_ytd_costs.quantity	:= r_ytd_costs.quantity
								+ tab_subcosts(i_index).quantity;
--		r_ytd_costs.type	  := r_ytd_costs.type;
		r_ytd_costs.amount	  := r_ytd_costs.amount
								+ tab_subcosts(i_index).amount;
	  END LOOP;

	  IF ( r_ytd_costs.amount = 0 ) THEN
		r_ytd_costs.type			:= 'A';
	  ELSE
		IF ( t_diff_type = TRUE) THEN
		  r_ytd_costs.type		  := 'B';
		ELSE
		  r_ytd_costs.type		  := 'C';
		END IF;
	  END IF;
	  PIPE ROW(r_ytd_costs);

	END IF;

  END LOOP;
  RETURN;
END;
/

اتمنى لك التوفيق ،،

الدرس منقول من الرابط .

#4

أشكرك أخي الكريم ، فعلاً هذا هو ما أحتاجة تماماً

وجزاك الله كل خير

بس لو سمحت ، أنا كنت عارض هذا الموضوع في منتديات أخري من 3 شهور تقريباً

سأرفق هذا الموضوع هناك وبأسلوبي الخاص حتي يستفيدون بها أعضاء المنتديات

وشكراً جزيراً

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#5

هناك طريقة أخرى تعتمد على nested table

وهي أولا نقوم بإنشاء غرض جديد object


i number,
n varchar2(30)
);
create or replace type t_col as object (

/

ومن ثم نقوم بإنشاء نوع nested table حيث نستفيد من الغرض السابق الذي يدل

على رقم الحقل field و على اسمه

create or replace type t_nested_table as table of t_col

;

/

وأخيرا ننشأ الوظيفة التي تعيد لنا الغرض من نوع table على النحو التالي :


v_ret t_nested_table;
begin
v_ret := t_nested_table();

v_ret.extend;
v_ret(v_ret.count) := t_col(1, 'one');

v_ret.extend;
v_ret(v_ret.count) := t_col(2, 'two');

v_ret.extend;
v_ret(v_ret.count) := t_col(3, 'three');

return v_ret;
end;
create or replace function return_table return t_nested_table as

/

وبكل بساطة نستخدم sql على النحو التالي :

select * from table(return_table);

#6

أخي **Start** ،

أشكرك كثيراً علي هذه الطريقة الجميلة ، وبالفعل هذا ما أبحث عنه منذ فترة طويلة.

لكن أخي الكريم ، ممكن توضحلي كيفية إستخدام Ref Cursor الذي أوضحه لي

الأخ IGBSpeed علي مثل هذا المثال ، لأن المثال الذي قمت بإضافته يتطلب مني

إنشاء Cursor وإجراء Loop عليه ، أما طريقة Ref Cursor أقوم بإعطاء جمله

إستعلام Select مباشرتاً دون الإحتياج الي إجراء دوارات علي البيانات .

وأشكرك مرة أخري ، بس ياريت تستجيب إلي بسرعة

وجزاك الله كل خير ، وجعلها في ميزان حسناتك يارب العالمين

علي العموم سأرفق مثال عام عن نفس الأسلوب الذي قمت بطرحة بإحدي مشاركاتك

وشكراً لك

***********************************************************************

رسالة الي مشرفين المنتدي الكرام ، أنا مشعارف أقول ماذا ، فحينما قمت بإضافة تعقيبي

هذا وجدت رسالة لي توضح بـ (عنوان الموضوع مهم لدرجة كبيرة - فلا تجعلنا نغلق لك

موضوعا - إضغط هنا لمعرفة قوانين الكتابة ) .

فأعتقد أن عنوان موضوعي مناسب جداً للمشكلة نفسها ، وأنا دائماً أحاول إيجاد عنوان

مناسب لموضوعاتي

أما إذا كان هذا الموضوع متكرر بسببي ، فصدقوني أنا لم أقصد .

فما هي المشكلة ؟ ياريت حد يستجيب إلي ؟

وشكراً

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#7

ها هو المثال

ReturnTableOnFunction.rar

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#8

أخي الكريم :

أول شي تعرف type من النوع المذكور على هذا الشكل :

CREATE OR REPLACE PACKAGE Types AS 
  TYPE cursor_type IS REF CURSOR;
END Types; 
/

من ثم نقوم بإعادته على الشكل التالي ضمن البارامتر التاني من البروسيجر :

CREATE OR REPLACE
PROCEDURE GetEmpRS (p_deptno	IN  emp.deptno%TYPE,
					p_recordset OUT Types.cursor_type) AS 
BEGIN 
  OPEN p_recordset FOR
	SELECT ename,
		   empno,
		   deptno
	FROM   emp
	WHERE  deptno = p_deptno
	ORDER BY ename;
END GetEmpRS;
/

من ثم نقوم بإعادة الريكوردات بأسهل طريق وهي على النحو التالي (حيث يهمك

أنت الجزء السابق ، ولكن هنا من أجل الأستفادة فقط )

DECLARE
  v_cursor  Types.cursor_type;
  v_ename   emp.ename%TYPE;
  v_empno   emp.empno%TYPE;
  v_deptno  emp.deptno%TYPE;
BEGIN
  GetEmpRS (p_deptno	=> 30,
			p_recordset => v_cursor);

  LOOP 
	FETCH v_cursor
	INTO  v_ename, v_empno, v_deptno;
	EXIT WHEN v_cursor%NOTFOUND;
	DBMS_OUTPUT.PUT_LINE(v_ename || ' | ' || v_empno || ' | ' || v_deptno);
  END LOOP;
  CLOSE v_cursor;
END;
/

حيث افترضت أنك تملك جدول للموظفين فيه فيلدات الرقم والقسم و الاسم ...

بالتوفيق

تم تعديل هذه المشاركة بواسطة **star** في 15 يوليو 2007 في 08:03

#9

أخي **Start** الكريم ، أشكرك كثيراً علي هذا الشرح الجميل ،

أمممممممممممممممم

بصراحة أنا مش عارف ماذا أقول لك ، بس بصراحة أنا لدي سؤال آخر متعلق بنفس الموضوع ، فأعزرني أخي الكريم ، فمن الواضح أنني مزعج لك كثيرا ، لكنني قمت بإنشاء كود أبسط من ذلك ، تم تنفيذه طبيعي ، ولكن لم أدري كيف يتم إستدعائة مثلما قمت أنت بإستدعائه سابقاً :

Select * From Table(<Function Name>);

علي العموم ها هو الكود ؟

Create Or Replace Package PKG
As
   Type R_EMP Is Ref Cursor;
   Function List_Emp(ID_Start Number,ID_End Number) Return R_EMP;
End;
/

Create Or Replace Package Body PKG
As
   Function List_Emp(ID_Start Number,ID_End Number) Return R_EMP
   As
	  REmp   R_EMP;
   Begin
	   Open REmp For Select * From Employee Where Emp_ID Between ID_Start And ID_End;
	   Return REmp;
   End;
End;
/

أما عن مشكلي ، فكيف أستخدم الغرض List_Emp الموجود داخل الحزمة PKG ، في جملة Select

وآسف مرة أخري علي الإزعاج

وشكراً

لا تخلط ما بين شخصيتي وأسلوبي .. فشخصيتي هي

ما أنا عليه وتحت تصرفي .. وأسلـوبي يعتمد عليـك

أنت وتصرفاتك

ولحظاتي صمت... وصمـت لحظاتي كلام ... كلامه

اشد آلام ... فصمتي أنا عنوان

عصر التكنولوجيا المعلوماتية(مدونتي الخاصة)

My FaceBook

#10

انت من الناحية العملية فقط تمرر للوظيفة رقم الموظف الأول و رقم الموظف الأخير و تعيد

كرسور ، و هذا فقط .... يعني

مثلا لو كان عندك أرقام موظفين بين 1 حتى 4000 ، وتريد منهم من 60 حتى 710 فيكون لديك

List_Emp(60,710)

وبما أن الوظيفة السابقة تعيد ريف كورسور فيكون لديك

v_cursor = List_Emp(60,710)

وتعمل نفس الحلقة يلي وضعتها بالمثال السابق

وشكرا

#11

يمكن عرض او استرجاع جدول معين عن طريق الكورسور

هذا المثال على جدول departments فى سكيما hr

declare

cursor dept_cur is

select department_id,department_name

,manager_id,location_id

from departments;

did number;

dname varchar2(20);

dmang number;

dloc number;

begin

open dept_cur;

loop

fetch dept_cur into did,dname,dmang,dloc ;

exit when dept_cur%notfound;

DBMS_OUTPUT.PUT_LINE( did||''||dname||''||dmang||''||dloc);

END LOOP;

close dept_cur;

end;

/

هذا الموضوع مغلق.

مواضيع مشابهة