คอลัมน์ที่คำนวณ / คำนวณ / เสมือน / ที่ได้รับใน PostgreSQL


113

PostgreSQL รองรับคอลัมน์ที่คำนวณ / คำนวณเช่น MS SQL Server หรือไม่ ฉันไม่พบสิ่งใดในเอกสาร แต่เนื่องจากคุณลักษณะนี้รวมอยู่ใน DBMS อื่น ๆ อีกมากมายฉันจึงคิดว่าอาจขาดอะไรไป

เช่น: http://msdn.microsoft.com/en-us/library/ms191250.aspx


การใช้นิพจน์เคียวรีย่อยด้านข้าง (ฟีเจอร์ Postgres) คุณสามารถเพิ่มคอลัมน์เพิ่มเติมในแต่ละแถวได้อย่างง่ายดาย
วิกเตอร์

คำตอบ:


139

ไม่รองรับคอลัมน์ที่สร้างขึ้น Postgres 11 คอลัมน์ - ตามที่กำหนดไว้ในมาตรฐาน SQL และใช้งานโดย RDBMS บางตัวรวมถึง DB2, MySQL และ Oracle หรือ"คอลัมน์จากการคำนวณ" ที่คล้ายกันของ SQL Server

STOREDคอลัมน์สร้างขึ้นจะถูกนำมาใช้กับPostgres 12 ตัวอย่างเล็กน้อย:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> ซอที่นี่

VIRTUALคอลัมน์ที่สร้างขึ้นอาจมาพร้อมกับหนึ่งในการทำซ้ำถัดไป (ยังไม่มีใน Postgres 13)

ที่เกี่ยวข้อง:


จนแล้วคุณสามารถเลียนแบบVIRTUALสร้างคอลัมน์ที่มีฟังก์ชั่นการใช้สัญกรณ์แอตทริบิวต์ ( tbl.col) ที่ลักษณะและทำงานเหมือนคอลัมน์สร้างเสมือน นั่นเป็นความแปลกทางไวยากรณ์เล็กน้อยที่มีอยู่ใน Postgres ด้วยเหตุผลทางประวัติศาสตร์และเหมาะสมกับกรณีนี้ คำตอบที่เกี่ยวข้องนี้มีตัวอย่างโค้ด :

แม้ว่านิพจน์ (ดูเหมือนคอลัมน์) จะไม่รวมอยู่ใน a SELECT * FROM tblแม้ว่า คุณต้องระบุไว้อย่างชัดเจนเสมอ

นอกจากนี้ยังสามารถได้รับการสนับสนุนด้วยการจับคู่ดัชนีแสดงออก - IMMUTABLEจัดให้มีฟังก์ชั่น ชอบ:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

ทางเลือก

หรือคุณสามารถใช้ฟังก์ชันการทำงานที่คล้ายกันกับ a VIEWซึ่งเป็นทางเลือกควบคู่กับดัชนีนิพจน์ จากนั้นSELECT *สามารถรวมคอลัมน์ที่สร้างขึ้น

STOREDคอลัมน์ที่คำนวณแล้ว"Persisted" ( ) สามารถนำไปใช้กับทริกเกอร์ได้ในลักษณะที่เหมือนกัน

มุมมองที่ปรากฏเป็นแนวคิดที่เกี่ยวข้องอย่างใกล้ชิดดำเนินการตั้งแต่ Postgres 9.3
ในเวอร์ชันก่อนหน้าเราสามารถจัดการ MV ได้ด้วยตนเอง


ขึ้นอยู่กับปริมาณข้อมูลที่คุณโหลดในครั้งเดียว .. ทริกเกอร์สามารถทำให้สิ่งต่างๆช้าลงอย่างมาก อาจต้องการพิจารณาการอัปเดตแทน
sam yi

1
โซลูชันเหล่านี้ค่อนข้างไร้ประโยชน์ (หากไม่มีการเปลี่ยนแปลงโค้ดขนาดใหญ่เป็น codebase โดยไม่มีกรณีทดสอบ) เมื่อย้ายจาก oracle ไปยัง postgres มีวิธีแก้ไขจากมุมมองของการโยกย้ายหรือไม่?
happybuddha

@happybuddha: ขอถามเป็นคำถาม ความคิดเห็นไม่ใช่สถานที่ คุณสามารถเชื่อมโยงไปยังคำถามนี้สำหรับบริบทได้ตลอดเวลา (และเพิ่มความคิดเห็นที่นี่เพื่อรับความสนใจของฉันและเชื่อมโยงไปยังคำถามที่เกี่ยวข้อง)
Erwin Brandstetter

4
ฟังก์ชันกำลังอยู่ในระหว่างการพัฒนา: commitfest.postgresql.org/16/1443
r90t

1
@cryanbhu: ขึ้นอยู่กับรายละเอียดของการตั้งค่าและความต้องการของคุณ คุณอาจถามคำถามใหม่พร้อมข้อมูลที่จำเป็น
Erwin Brandstetter

32

ใช่คุณสามารถ!! วิธีแก้ปัญหาควรง่ายปลอดภัยและมีประสิทธิภาพ ...

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

สมมติว่าการคำนวณของฉันคือmd5(some_string_field)จากนั้นฉันสร้างดัชนีเป็น:

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

ตอนนี้การสืบค้นใด ๆ ที่ดำเนินการMD5(some_string_field)จะใช้ดัชนีแทนที่จะคำนวณตั้งแต่ต้น ตัวอย่างเช่น:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

คุณสามารถตรวจสอบนี้กับอธิบาย

อย่างไรก็ตาม ณ จุดนี้คุณต้องพึ่งพาผู้ใช้ตารางที่รู้วิธีสร้างคอลัมน์อย่างแน่นอน เพื่อให้ชีวิตง่ายขึ้นคุณสามารถสร้างVIEWตารางเดิมลงในเวอร์ชันเสริมโดยเพิ่มค่าที่คำนวณเป็นคอลัมน์ใหม่:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

ตอนนี้ข้อความค้นหาใด ๆ ที่ใช้some_table_augmentedจะสามารถใช้งานได้some_string_field_md5โดยไม่ต้องกังวลว่าจะทำงานอย่างไร.. เพียงแค่ได้รับประสิทธิภาพที่ดี มุมมองไม่ได้คัดลอกข้อมูลใด ๆ จากตารางต้นฉบับดังนั้นจึงเป็นการดีที่มีหน่วยความจำและประสิทธิภาพที่ชาญฉลาด อย่างไรก็ตามโปรดทราบว่าคุณไม่สามารถอัปเดต / แทรกลงในมุมมองได้เฉพาะในตารางต้นทาง แต่ถ้าคุณต้องการจริงๆฉันเชื่อว่าคุณสามารถเปลี่ยนเส้นทางการแทรกและการอัปเดตไปยังตารางต้นทางโดยใช้กฎ (ฉันอาจผิดในจุดสุดท้ายนั้นเป็น ยังไม่เคยลองเอง).

แก้ไข:ดูเหมือนว่าหากแบบสอบถามเกี่ยวข้องกับดัชนีที่แข่งขันกันเครื่องมือวางแผนบางครั้งอาจไม่ใช้ดัชนีนิพจน์เลย ตัวเลือกดูเหมือนจะขึ้นอยู่กับข้อมูล


1
คุณช่วยอธิบายหรือยกตัวอย่างได้if the query involves competing indicesไหม
dvtan

17

วิธีหนึ่งที่ทำได้คือใช้ไก!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

ทริกเกอร์จะเริ่มทำงานก่อนที่จะอัปเดตหรือแทรกแถว มันเปลี่ยนฟิลด์ที่เราต้องการคำนวณเรกคอร์ดจากNEWนั้นจะส่งกลับเรกคอร์ดนั้น


ทริกเกอร์จะยิงเมื่อใด ฉันวิ่งไปข้างบนและทำสิ่งนี้insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;และมันก็กลับมา: 1 2 และ 4 8
happybuddha

2
ลองinsert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;ค่าของtwoคอลัมน์จะถูกคำนวณโดยอัตโนมัติ!
Elmer

8

PostgreSQL 12 รองรับคอลัมน์ที่สร้างขึ้น:

PostgreSQL 12 Beta 1 เปิดตัวแล้ว!

คอลัมน์ที่สร้างขึ้น

PostgreSQL 12 อนุญาตให้สร้างคอลัมน์ที่สร้างขึ้นซึ่งคำนวณค่าด้วยนิพจน์โดยใช้เนื้อหาของคอลัมน์อื่น คุณลักษณะนี้มีคอลัมน์ที่สร้างขึ้นที่จัดเก็บไว้ซึ่งคำนวณจากส่วนแทรกและการอัปเดตและบันทึกไว้ในดิสก์ คอลัมน์ที่สร้างขึ้นเสมือนซึ่งคำนวณเฉพาะเมื่อคอลัมน์ถูกอ่านเป็นส่วนหนึ่งของแบบสอบถามยังไม่ได้ใช้งาน


คอลัมน์ที่สร้างขึ้น

คอลัมน์ที่สร้างขึ้นคือคอลัมน์พิเศษที่คำนวณจากคอลัมน์อื่นเสมอ ดังนั้นสำหรับคอลัมน์ที่มีมุมมองสำหรับตาราง

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> การสาธิตซอ



1

ไม่แน่ใจว่านี่คือสิ่งที่คุณหมายถึงหรือไม่ แต่ Posgres รองรับไวยากรณ์ ETL แบบ "dummy" ฉันสร้างคอลัมน์ว่างหนึ่งคอลัมน์ในตารางจากนั้นจำเป็นต้องเติมด้วยระเบียนที่คำนวณโดยขึ้นอยู่กับค่าในแถว

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. มันหลอกตามากฉันสงสัยว่ามันไม่ใช่สิ่งที่คุณกำลังมองหา
  2. เห็นได้ชัดว่ามันไม่ได้เป็นแบบไดนามิกคุณเรียกใช้ครั้งเดียว แต่ไม่มีอุปสรรคที่จะทำให้มันเป็นทริกเกอร์

0

ฉันมีรหัสที่ใช้งานได้และใช้คำที่คำนวณได้ฉันไม่ได้ใช้ postgresSQL ล้วนๆที่เราทำงานบน PADB

นี่คือวิธีการใช้งาน

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;

PADB คืออะไร?
Gherman

ParAccel Analytic Database มันเก่า แต่ดี ... th.wikipedia.org/wiki/ParAccel
Wired604

แต่มันเกี่ยวข้องกับคำถามเกี่ยวกับ Postgres อย่างไร? แน่ใจว่ามีฐานข้อมูลจำนวนมากที่รองรับคอลัมน์จากการคำนวณ
Gherman

อาขอโทษฉันไม่ได้ใช้เวลาในการย้อนกลับไปในบริบท .... PADB ขึ้นอยู่กับความคืบหน้า!
Wired604

-6

โซลูชันที่มีน้ำหนักเบาพร้อมข้อ จำกัด ในการตรวจสอบ:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
สิ่งนี้เกี่ยวข้องกับแนวคิดของคอลัมน์จากการคำนวณอย่างไร? คุณช่วยอธิบายได้ไหม
Erwin Brandstetter

4
ตกลงมันไม่เกี่ยวข้องโดยตรง แต่จะทดแทนกรณีที่เรียบง่ายเมื่อคุณเพียงแค่ต้องทำ somthing field as 1 persistedเช่น
cinereo

2
คำอธิบายน่าจะดีมาก ฉันคิดว่าคำตอบนี้คือถ้าการคำนวณสามารถทำได้ด้วยประโยคเริ่มต้นคุณสามารถใช้ค่าเริ่มต้นและข้อ จำกัด ในการตรวจสอบเพื่อป้องกันไม่ให้ใครเปลี่ยนค่าได้
Ross Bradbury

@ Ross Bradbury: เห็นด้วย แต่ใช้ได้กับการแทรกเท่านั้น จะไม่ทำงานหากมีการอัปเดตคอลัมน์ที่เกี่ยวข้อง
Stefan Steiger
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.