วิธีโยกย้าย SQL Server Stored Procedure โดยใช้ตารางชั่วคราวหรือตัวแปรตารางไปยัง Oracle


9

ผู้พัฒนา C # ได้รับการสนับสนุนโดยฝ่ายบริหารให้เขียนขั้นตอนการจัดเก็บ SQL Server มักจะสร้างขั้นตอนเช่นนี้

create table #t1 (...);
insert into #t1 Select ... from table_a where ...;
insert into #t1 Select ... from table_b where ...;
update #t1 Set ... = ... where ...
Select * from #t1;

คำสั่งเดียวค่อนข้างง่ายและวิธีนี้ทำให้พวกเขาผลิตผลลัพธ์ที่ถูกต้อง

บ่อยครั้งที่งานของฉันคือการโยกย้ายขั้นตอนดังกล่าวไปยัง Oracle

ลองหน้าข้อเท็จจริงต่อไปนี้

  • สำหรับตารางชั่วคราวที่แตกต่างกันใน SQL Server นั้นมีความเป็นอิสระอย่างสมบูรณ์และสามารถมีโครงสร้างแบบเฉพาะกิจได้
  • ตารางทั่วโลกของ Oracle เป็นออบเจ็กต์ร่วมและทั้งหมดใช้โครงสร้างตารางร่วมกันมาก การแก้ไขโครงสร้างนี้เป็นไปไม่ได้ในขณะที่ใช้งานได้ทุกที่

สิ่งหนึ่งที่ฉันเรียนรู้จาก Oracle dba คือการหลีกเลี่ยงการใช้ตารางชั่วคราวทุกครั้งที่ทำได้ แม้แต่ประสิทธิภาพบนเซิร์ฟเวอร์ SQL ก็ยังได้รับประโยชน์จากการดัดแปลง

แทนที่เม็ดมีดแต่ละอันด้วยสหภาพ

ในกรณีที่ง่ายที่สุดสิ่งที่กล่าวมาสามารถเปลี่ยนเป็นสิ่งที่ชอบ

select case when ... then ... end, ... from table_a where ...
union
select case when ... then ... end, ... from table_b where ...
Order by ...;

การใช้ฟังก์ชั่น

ทั้งฟังก์ชั่นสเกลาร์และฟังก์ชั่นที่มีคุณค่าของตารางสามารถช่วยเปลี่ยนโพรซีเดอร์ของคุณให้เป็นคิวรีเดียวของแบบฟอร์มด้านบน

นิพจน์ตารางทั่วไป aka แฟ็คเคอร์ย่อย

Factoring Subquery เกือบจะเป็นออราเคิลที่ดีที่สุดที่มีให้เพื่อหลีกเลี่ยงตารางชั่วคราว การใช้การโยกย้ายของ SQL Server ไปยัง Oracle นั้นค่อนข้างง่าย สิ่งนี้ต้องใช้ SQL Server 2005 ขึ้นไป


การปรับเปลี่ยนเหล่านี้ปรับปรุงรุ่นของ SQL Server และในหลาย ๆ กรณีทำให้การโยกย้ายตรงไปข้างหน้า ในกรณีอื่น ๆ หันไปใช้ตารางชั่วคราวทั่วโลกทำให้สามารถทำการย้ายข้อมูลในเวลาที่กำหนด แต่ก็ไม่เป็นที่น่าพอใจ


มีวิธีอื่นอีกหรือไม่ในการหลีกเลี่ยงการใช้ตารางชั่วคราวทั่วโลกใน Oracle?


3
ฉันจะบอกว่ารหัสเช่นนั้นเป็นสิ่งบ่งบอกถึงขั้นตอนการคิดที่ไม่ได้ตั้งค่า และนี่คือตาราง temp ของเครื่องที่มีค่าเดียว ผมจัดการและฉันต้องการทำลายขาถ้าผมเห็นว่าจะเข้าสู่การผลิต :-)
GBN

ฉันเห็นด้วยอย่างสมบูรณ์
bernd_k

@gbn - Idiomatic PL / SQL มีแนวโน้มที่จะเป็นขั้นตอนเล็กน้อยกว่า T-SQL ที่ใช้สำนวน ตารางชั่วคราวทำให้สามารถทำเกือบทุกอย่างใน set ops ใน T-SQL PL / SQL มี ops เคอร์เซอร์แบบขนานและฟังก์ชันการทำงานอื่น ๆ อีกมากมายสำหรับการปรับรหัสขั้นตอนให้เหมาะสม
ConcOfOfTunbridgeWells

คำตอบ:


3

วิธีหนึ่งในการทำเช่นนี้ก็คือประเภทวัตถุในกรณีนี้ประเภทจะเป็นของคุณ#t1ได้ ดังนั้นมันจะต้องมีการกำหนดไว้ที่ไหนสักแห่งแต่มันไม่จำเป็นต้องเป็นโลกมันอาจจะเป็นต่อสคีมาหรือต่อขั้นตอนแม้ ก่อนอื่นเราสามารถสร้างประเภท:

SQL> create or replace type t1_type as object (x int, y int, z int)
  2  /

Type created.

SQL> create or replace type t1 as table of t1_type
  2  /

Type created.

ตอนนี้ตั้งค่าข้อมูลตัวอย่างบางส่วน:

SQL> create table xy (x int, y int)
  2  /

Table created.

SQL> insert into xy values (1, 2)
  2  /

1 row created.

SQL> insert into xy values (3, 4)
  2  /

1 row created.

SQL> commit
  2  /

Commit complete.

และสร้างฟังก์ชั่นเหนือข้อมูลนี้ที่ส่งคืนชนิด "ชั่วคราว" ของเรา:

SQL> create or replace function fn_t1 return t1 as
  2  v_t1 t1 := t1();       -- empty temporary table (really an array)
  3  v_ix number default 0; -- array index
  4  begin
  5  for r in (select * from xy) loop
  6  v_ix := v_ix + 1;
  7  v_t1.extend;
  8  v_t1(v_ix) := t1_type(r.x, r.y, (r.x + r.y));
  9  end loop;
 10  return v_t1;
 11  end;
 12  /

Function created.

และในที่สุดก็:

SQL> select * from the (select cast (fn_t1 as t1) from dual)
  2  /

         X          Y          Z
---------- ---------- ----------
         1          2          3
         3          4          7

อย่างที่คุณเห็นนี่เป็น clunky สวย (และใช้ฟังก์ชั่นการหลอกคอลเลกชันซึ่งเป็นคุณลักษณะที่คลุมเครือในเวลาที่ดีที่สุด!) อย่างที่ฉันพูดเสมอว่าการย้ายจาก DB ไปยัง DB ไม่ใช่แค่เรื่องไวยากรณ์และคำหลักในภาษา SQL ความยากลำบากที่แท้จริงเกิดขึ้นในข้อสมมติฐานพื้นฐานที่แตกต่างกัน (ในกรณีของ SQL Server เคอร์เซอร์นั้นมีราคาแพงและการหลีกเลี่ยง / หลีกเลี่ยงการใช้งานโดยไม่เสียค่าใช้จ่าย)


3

หากตัวเลือกกรณีไม่ยืดหยุ่นพอคุณสามารถรวบรวมข้อมูลจำนวนมากในกระบวนการของคุณและจัดการกับอาร์เรย์

--Setup
CREATE TABLE table_a (c1 Number(2));
CREATE TABLE table_b (c1 Number(2));
INSERT INTO table_a (SELECT rownum FROM dual CONNECT BY rownum<=4);
INSERT INTO table_b (SELECT rownum+5 FROM dual CONNECT BY rownum<=4);

--Example
DECLARE
   Type tNumberArray Is Table Of Number;
   v1 tNumberArray;
BEGIN
   SELECT c1 BULK COLLECT INTO v1 FROM (
      SELECT c1 FROM table_a
      UNION ALL
      SELECT c1 FROM table_b
      );

   For x IN v1.First..v1.Last Loop
      /* Complex manipulation goes here. */
      If (v1(x) <= 3) Then
         v1(x) := v1(x)*10;
      End If;
      DBMS_OUTPUT.PUT_LINE(v1(x));
   End Loop;
END;
/

+1 แต่สิ่งนี้จะไม่ส่งคืนชุดผลลัพธ์ (หาก a SELECTคือสิ่งสุดท้ายใน proc ที่จัดเก็บของ T-SQL นั่นคือสิ่งที่ส่งคืน)
Gaius

หากบล็อกรหัสนี้เปลี่ยนเป็นโพรซีเดอร์คุณสามารถส่งคืนอาร์เรย์หรือเปิดอาร์เรย์เป็นเคอร์เซอร์และส่งเคอร์เซอร์กลับหรือแม้แต่ทำให้มันเป็นฟังก์ชันและไพพ์แบ็กแถว แต่ละเหล่านี้จะคล้ายกัน แต่ที่คุณควรใช้จะขึ้นอยู่กับสถานการณ์
Leigh Riffel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.