পোস্টগ্রিসে বিদ্যমান কলামে 'সিরিয়াল' যুক্ত করা হচ্ছে


98

আমার পোস্টগ্রিজ 9.0 ডাটাবেসে একটি পূর্ণসংখ্যার ID ক্ষেত্র (প্রাথমিক কী) সহ একটি ছোট টেবিল (~ 30 টি সারি) রয়েছে যা বর্তমানে 1 থেকে শুরু করে অনন্য ক্রমক্রমিক পূর্ণসংখ্যা রয়েছে, যা 'সিরিয়াল' কীওয়ার্ড ব্যবহার করে তৈরি করা হয়নি।

আমি কীভাবে এই টেবিলটিকে এমনভাবে পরিবর্তন করতে পারি যে এখন থেকে এই টেবিলের সন্নিবেশ করানো এই ক্ষেত্রটিকে এমনভাবে আচরণ করবে যাতে এটি 'সিরিয়াল' দিয়ে টাইপ হিসাবে তৈরি করা হয়েছিল?


4
এফওয়াইআই, SERIALসিউডো-টাইপটি এখন লিগ্যাসি , এসকিউএল: 2003 এ পোস্টগ্রিস 10 এবং তারপরে সংজ্ঞায়িত নতুন GENERATED … AS IDENTITYবৈশিষ্ট্য দ্বারা সরবরাহ করা হয়েছে । ব্যাখ্যা দেখুন ।
তুলসী বাউরক

: আধুনিক Postgres সংস্করণের জন্য (> = 10) এই প্রশ্ন দেখতে পাবেন stackoverflow.com/questions/2944499
a_horse_with_no_name

উত্তর:


135

নিম্নলিখিত কমান্ডগুলি দেখুন (বিশেষত মন্তব্য করা ব্লক)

DROP TABLE foo;
DROP TABLE bar;

CREATE TABLE foo (a int, b text);
CREATE TABLE bar (a serial, b text);

INSERT INTO foo (a, b) SELECT i, 'foo ' || i::text FROM generate_series(1, 5) i;
INSERT INTO bar (b) SELECT 'bar ' || i::text FROM generate_series(1, 5) i;

-- blocks of commands to turn foo into bar
CREATE SEQUENCE foo_a_seq;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
ALTER TABLE foo ALTER COLUMN a SET NOT NULL;
ALTER SEQUENCE foo_a_seq OWNED BY foo.a;    -- 8.2 or later

SELECT MAX(a) FROM foo;
SELECT setval('foo_a_seq', 5);  -- replace 5 by SELECT MAX result

INSERT INTO foo (b) VALUES('teste');
INSERT INTO bar (b) VALUES('teste');

SELECT * FROM foo;
SELECT * FROM bar;

যেহেতু আপনি আপনার ওপিতে প্রাথমিক কীগুলি উল্লেখ করছেন, আপনি এটি করতেও চাইতে পারেন ALTER TABLE foo ADD PRIMARY KEY (a)
স্কিপি লে গ্র্যান্ড গৌরু

সিরিয়াল সিনট্যাকটিক চিনি এবং ডিবি মেটাডেটাতে সংরক্ষণ করা হয় না, সুতরাং উপরের কোডটি 100% সমতুল্য হবে।
DKroot

যদি কোনও সুযোগ থাকে যে লক্ষ্য ব্যবহারের টেবিলটি অন্য কোনও ব্যবহারকারী দ্বারা তৈরি করা হয়েছিল, আপনাকে ALTER TABLE foo OWNER TO current_user;প্রথমে এটি করতে হবে ।
DKroot

4
আপনি কি সেটআপ করা উচিত না MAX(a)+1? SELECT MAX(a)+1 FROM foo; SELECT setval('foo_a_seq', 6);
সানিপ্রো

50

আপনি START WITHএকটি নির্দিষ্ট বিন্দু থেকে ক্রম শুরু করতেও ব্যবহার করতে পারেন , যদিও সেটল একই জিনিস সম্পাদন করেছেন, যেমন ইউলারের উত্তর, যেমন,

SELECT MAX(a) + 1 FROM foo;
CREATE SEQUENCE foo_a_seq START WITH 12345; -- replace 12345 with max above
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');

31

টিএল; ডিআর

এখানে এমন একটি সংস্করণ রয়েছে যেখানে কোনও মান পড়তে এবং সেগুলি টাইপ করার জন্য আপনার কোনও মানুষের প্রয়োজন হয় না।

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq'); 

আরেকটি বিকল্প হ'ল Functionএই উত্তরটির শেষে পুনরায় ব্যবহারযোগ্য ভাগ করে নেওয়া নিয়োগ করা ।


একটি অ ইন্টারেক্টিভ সমাধান

উদাহরণস্বরূপ লাইভ-ইশ ডিবি প্যাচিংয়ের সময় আমাদের মধ্যে যারা এইগুলি Sequenceএকটি অ-ইন্টারেক্টিভ স্ক্রিপ্ট দ্বারা তৈরি করা দরকার তাদের জন্য কেবলমাত্র অন্য দুটি জবাব যুক্ত করুন ।

এটি হ'ল, যখন আপনি SELECTমানটি নিজে হাতে পেতে চান না এবং এটিকে পরবর্তী CREATEবিবৃতিতে নিজেকে টাইপ করুন ।

সংক্ষেপে, আপনি এটি করতে পারবেন না :

CREATE SEQUENCE foo_a_seq
    START WITH ( SELECT max(a) + 1 FROM foo );

... যেহেতু START [WITH]মধ্যে দফা CREATE SEQUENCEপ্রত্যাবর্তনের একটি মান , না একটি subquery।

নোট: (একটি চলতি নিয়ম, এর সমস্ত অ-টি ককটেলের প্রযোজ্য হিসাবে অর্থাত : ছাড়া আর কিছু INSERT, SELECT, UPDATE, DELETEমধ্যে বিবৃতির) pgSQL আমি যতদূর জানি।

যাইহোক, setval()না! সুতরাং, নিম্নলিখিতটি নিখুঁত:

SELECT setval('foo_a_seq', max(a)) FROM foo;

যদি কোনও ডেটা না থাকে এবং আপনি এটি সম্পর্কে জানতে (চান না), coalesce()ডিফল্ট মান সেট করতে ব্যবহার করুন :

SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
--                         ^      ^         ^
--                       defaults to:       0

তবে, বর্তমান সিকোয়েন্স মান সেট করা 0বেআইনী না হলে আনাড়ি is
এর থ্রি-প্যারামিটার ফর্মটি ব্যবহার setvalকরা আরও উপযুক্ত হবে:

--                                             vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
--                                                  ^   ^
--                                                is_called

ঐচ্ছিক তৃতীয় প্যারামিটারটি সেট setvalকরার falseপরের প্রতিরোধ করবে nextvalএকটি মান ফেরার আগে ক্রম আগুয়ান থেকে, এবং এইভাবে:

পরবর্তীটি nextvalনিখুঁতভাবে নির্দিষ্ট মানটি ফেরত দেবে এবং ক্রম অগ্রগতি নিম্নলিখিতটির সাথে শুরু হয় nextval

- ডকুমেন্টেশনে এই এন্ট্রি থেকে

কোনও সম্পর্কযুক্ত নোটে, আপনি Sequenceসরাসরি কলামটির সাথে কলামটিও নির্দিষ্ট করতে পারবেন CREATE, আপনাকে পরে এটি পরিবর্তন করতে হবে না:

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;

সংক্ষেপে:

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq'); 

ব্যবহার করে একটি Function

বিকল্পভাবে, আপনি যদি একাধিক কলামের জন্য এটি করার পরিকল্পনা করে থাকেন তবে আপনি একটি প্রকৃত ব্যবহারের বিকল্প বেছে নিতে পারেন Function

CREATE OR REPLACE FUNCTION make_into_serial(table_name TEXT, column_name TEXT) RETURNS INTEGER AS $$
DECLARE
    start_with INTEGER;
    sequence_name TEXT;
BEGIN
    sequence_name := table_name || '_' || column_name || '_seq';
    EXECUTE 'SELECT coalesce(max(' || column_name || '), 0) + 1 FROM ' || table_name
            INTO start_with;
    EXECUTE 'CREATE SEQUENCE ' || sequence_name ||
            ' START WITH ' || start_with ||
            ' OWNED BY ' || table_name || '.' || column_name;
    EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN ' || column_name ||
            ' SET DEFAULT nextVal(''' || sequence_name || ''')';
    RETURN start_with;
END;
$$ LANGUAGE plpgsql VOLATILE;

এটি এর মতো ব্যবহার করুন:

INSERT INTO foo (data) VALUES ('asdf');
-- ERROR: null value in column "a" violates not-null constraint

SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
-- OK: 1 row(s) affected

দুর্দান্ত উত্তর, তবে মনে রাখবেন coalesce(max(a), 0))বেশিরভাগ সময় কাজ করবে না, যেহেতু আইডিগুলি সাধারণত 1 থেকে শুরু হয় More আরও সঠিক coalesce(max(a), 1))
উপায়টি

4
মন্তব্যের জন্য আমিকো ধন্যবাদ! setvalফাংশন আসলে শুধুমাত্র ক্রম জন্য বর্তমান "সর্বশেষ ব্যবহৃত মান" সেট করে। পরবর্তী উপলভ্য মান (প্রথমে ব্যবহারের জন্য প্রথম) আরও একটি হবে! ব্যবহার setval(..., coalesce(max(a), 1))একটি খালি কলামে 'শুরু' সঙ্গে এটি সেট আপ হবে 2, (পরবর্তী উপলব্ধ মান) যেমন দেখানো ডকুমেন্টেশন
ccjmne

4
@ আমিকো আপনি ঠিক বলেছেন যে আমার কোডে কোনও সমস্যা আছে, যদিও: এটি currvalকখনই হওয়া উচিত নয় 0, এমনকি যদি এটি আসল ডাটাবেসে প্রতিফলিত না হয়। তিন প্যারামিটার ফর্মটি ব্যবহার করলে setvalতা আরও সঠিক হতে হবে: setval(..., coalesce(max(a), 0) + 1, false)। উত্তর অনুসারে আপডেট!
ccjmne

4
রাজি, আমি পুরোপুরি এটি মিস করেছি missed উত্তরের জন্য ধন্যবাদ আমার সময় সাশ্রয়।
Amiko
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.