यह संभव है कि किसी तालिका में, कुछ फ़ील्ड जिसमें बार-बार मान हों, उसे अद्वितीय के रूप में छोड़ने के लिए आवश्यक है।
और उन सभी को समाप्त किए बिना दोहराए गए मानों के साथ कैसे आगे बढ़ें?
क्या यह संभव होगा कि केवल सबसे वर्तमान छोड़ दें ?
ctid सिस्टम कॉलम
प्रत्येक तालिका में कुछ कॉलम होते हैं जो सिस्टम द्वारा परोक्ष रूप से परिभाषित होते हैं, जिनके नाम आरक्षित होते हैं।
वर्तमान में सिस्टम कॉलम हैं:टेबलॉइड, xmin, cmin, xmax, cmax और ctid। प्रत्येक के पास तालिका से मेटाडेटा होता है जिससे वे संबंधित होते हैं।
सीटीआईडी सिस्टम कॉलम का उद्देश्य पंक्ति के भौतिक स्थान के संस्करण को संग्रहीत करना है। यह संस्करण बदल सकता है यदि पंक्ति
अद्यतन (अद्यतन) या तालिका एक VACUUM पूर्ण के माध्यम से जाती है।
ctid का डेटा प्रकार tid है, जिसका अर्थ है टपल पहचानकर्ता (या पंक्ति पहचानकर्ता), जो एक है जोड़ी (ब्लॉक संख्या, ब्लॉक के भीतर टपल इंडेक्स)
जो तालिका के भीतर पंक्ति के भौतिक स्थान की पहचान करता है।
इस कॉलम का तालिका में हमेशा अपना विशिष्ट मान होता है, इसलिए जब बार-बार मानों वाली पंक्तियाँ हों इसे उनके उन्मूलन के मानदंड के रूप में इस्तेमाल किया जा सकता है।
टेस्ट टेबल बनाना:
CREATE TABLE tb_test_ctid (
col1 int,
col2 text);
कुछ डेटा डालें:
INSERT INTO tb_test_ctid VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');
वर्तमान पंक्तियों की जाँच करें:
SELECT ctid, * FROM tb_test_ctid;
ctid | col1 | col2 -------+------+------ (0,1) | 1 | foo (0,2) | 2 | bar (0,3) | 3 | baz
एक पंक्ति अपडेट करें:
UPDATE tb_test_ctid SET col2 = 'spam' WHERE col1 = 1;
तालिका को दोबारा जांचें:
SELECT ctid, * FROM tb_test_ctid;
ctid | col1 | col2 -------+------+------ (0,2) | 2 | bar (0,3) | 3 | baz (0,4) | 1 | spam
हम देख सकते हैं कि अपडेट की गई पंक्ति का ctid भी बदल गया था…
एक साधारण वैक्यूम पूर्ण परीक्षण:
VACUUM FULL tb_test_ctid;
VACUUM के बाद तालिका की जाँच करना:
SELECT ctid, * FROM tb_test_ctid;
ctid | col1 | col2 -------+------+------ (0,1) | 2 | bar (0,2) | 3 | baz (0,3) | 1 | spam
रिटर्निंग क्लॉज का उपयोग करके उसी पंक्ति को फिर से अपडेट करें:
UPDATE tb_test_ctid
SET col2 = 'eggs'
WHERE col1 = 1
RETURNING ctid;
ctid ------- (0,4)
तालिका को दोबारा जांचें:
SELECT ctid, * FROM tb_test_ctid;
ctid | col1 | col2 -------+------+------ (0,2) | 2 | bar (0,3) | 3 | baz (0,4) | 1 | spam
ctid के साथ बार-बार होने वाले मानों को खत्म करना
एक तालिका की कल्पना करें जिसमें किसी फ़ील्ड में बार-बार मान हैं और उसी फ़ील्ड को बाद में अद्वितीय बनाने का निर्णय लिया गया है।
याद रखें कि प्राथमिक कुंजी फ़ील्ड भी अद्वितीय है।
ठीक है, यह निर्णय लिया गया था कि इसमें दोहराए गए मान उस फ़ील्ड को हटा दिया जाएगा।
अब इन दोहराए गए मानों के बीच निर्णय लेने के लिए एक मानदंड स्थापित करना आवश्यक है जो बना रहेगा।
निम्नलिखित मामले में, मानदंड सबसे वर्तमान लाइन है, जो कि एक है उच्चतम ctid मान.
नई परीक्षण तालिका निर्माण:
CREATE TABLE tb_foo(
id_ int, --This field will be the primary key in the future!
letter char(1)
);
10 रिकॉर्ड डालें:
INSERT INTO tb_foo (id_, letter) SELECT generate_series(1, 10), 'a';
तालिका जांचें:
SELECT id_, letter FROM tb_foo;
id_ | letter -----+-------- 1 | a 2 | a 3 | a 4 | a 5 | a 6 | a 7 | a 8 | a 9 | a 10 | a3 और रिकॉर्ड डालें:
INSERT INTO tb_foo (id_, letter) SELECT generate_series(1, 3), 'b';
दोहराए गए मानों की जाँच करें:
SELECT id_, letter FROM tb_foo WHERE id_ <= 3;
id_ | letter -----+-------- 1 | a 2 | a 3 | a 1 | b 2 | b 3 | b
तालिका के id_ फ़ील्ड में बार-बार मान होते हैं…
id_ फ़ील्ड को प्राथमिक कुंजी बनाने का प्रयास करें:
ALTER TABLE tb_foo ADD CONSTRAINT tb_foo_pkey PRIMARY KEY (id_);
ERROR: could not create unique index "tb_foo_pkey" DETAIL: Key (id_)=(3) is duplicated.
सीटीई और विंडो फंक्शंस का उपयोग करते हुए पता करें कि कौन से दोहराए गए मान रखे जाएंगे:
WITH t AS (
SELECT
id_,
count(id_) OVER (PARTITION BY id_) AS count_id, -- Count
ctid,
max(ctid) OVER (PARTITION BY id_) AS max_ctid -- Most current ctid
FROM tb_foo
)
SELECT
t.id_,
t.max_ctid
FROM t
WHERE t.count_id > 1 -- Filters which values repeat
GROUP by id_, max_ctid;
id_ | max_ctid -----+---------- 3 | (0,13) 1 | (0,11) 2 | (0,12)
id_ फ़ील्ड के लिए अद्वितीय मानों वाली तालिका को छोड़कर, पुरानी पंक्तियों को हटा दें:
WITH
t1 AS (
SELECT
id_,
count(id_) OVER (PARTITION BY id_) AS count_id,
ctid,
max(ctid) OVER (PARTITION BY id_) AS max_ctid
FROM tb_foo
),
t2 AS ( -- Virtual table that filters repeated values that will remain
SELECT t1.id_, t1.max_ctid
FROM t1
WHERE t1.count_id > 1
GROUP by t1.id_, t1.max_ctid)
DELETE -- DELETE with JOIN
FROM tb_foo AS f
USING t2
WHERE
f.id_ = t2.id_ AND -- tb_foo has id_ equal to t2 (repeated values)
f.ctid < t2.max_ctid; -- ctid is less than the maximum (most current)
id_:
. के लिए डुप्लीकेट मानों के बिना तालिका मानों की जाँच करनाSELECT id_, letter FROM tb_foo;
id_ | letter -----+-------- 4 | a 5 | a 6 | a 7 | a 8 | a 9 | a 10 | a 1 | b 2 | b 3 | b
अब आप id_ फ़ील्ड को प्राथमिक कुंजी के रूप में छोड़ने के लिए तालिका को बदल सकते हैं:
ALTER TABLE tb_foo ADD CONSTRAINT tb_foo_pkey PRIMARY KEY (id_);