আমি কীভাবে কোনও সারণিতে একটি সারি আপডেট করব বা যদি এটি উপস্থিত না থাকে তবে এটি প্রবেশ করান?


84

আমার কাছে কাউন্টারগুলির নিম্নলিখিত সারণি রয়েছে:

CREATE TABLE cache (
    key text PRIMARY KEY,
    generation int
);

আমি কাউন্টারগুলির মধ্যে একটিকে বাড়িয়ে দিতে চাই বা সংশ্লিষ্ট সারিটি উপস্থিত না থাকলে শূন্যে সেট করতে চাই। স্ট্যান্ডার্ড এসকিউএলে সম্মতিযুক্ত সমস্যাগুলি ছাড়াই এটি করার কোনও উপায় আছে কি? অপারেশন কখনও কখনও লেনদেনের অংশ, কখনও কখনও পৃথক।

যদি সম্ভব হয় তবে এসকিউএল অবশ্যই এসকিউএল, পোস্টগ্রেএসকিউএল এবং মাইএসকিউএলে অপরিবর্তিতভাবে চালাতে হবে।

একটি অনুসন্ধানে বেশ কয়েকটি ধারণা পাওয়া গেছে যা হয় সম্মতিমূলক সমস্যাগুলির সাথে ভুগছে বা একটি ডেটাবেসের সাথে নির্দিষ্ট:

  • INSERTএকটি নতুন সারিতে চেষ্টা করুন , এবং UPDATEযদি কোনও ত্রুটি ছিল। দুর্ভাগ্যক্রমে, INSERTবর্তমান লেনদেনটি বাতিল করে দেওয়ার ত্রুটি ।

  • UPDATEসারি, এবং কোনও সারি পরিবর্তিত না হলে INSERTএকটি নতুন সারি।

  • মাইএসকিউএলের একটি ON DUPLICATE KEY UPDATEধারা রয়েছে use

সম্পাদনা: দুর্দান্ত উত্তরগুলির জন্য ধন্যবাদ। দেখে মনে হচ্ছে পল ঠিকই আছেন এবং এটি করার কোনও একক, পোর্টেবল উপায় নেই। এটি আমার কাছে বেশ আশ্চর্যজনক, কারণ এটি খুব বেসিক অপারেশন বলে মনে হচ্ছে।


6
আপনি কোনও একক সমাধান আবিষ্কার করতে যাচ্ছেন না যা এই সমস্ত আরডিবিএমএসের জন্য কাজ করে। দুঃখিত
পল টমলিন ২


উত্তর:


139

মাইএসকিউএল (এবং পরবর্তীকালে এসকিউএলাইট) এছাড়াও সিনট্যাক্সের পরিবর্তে সমর্থন করে:

REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');

এটি স্বয়ংক্রিয়ভাবে প্রাথমিক কীটি সনাক্ত করে এবং আপডেট করার জন্য একটি সাদৃশ্য সারিটি আবিষ্কার করে, যদি কোনওটি না পাওয়া যায় তবে একটি নতুন সন্নিবেশ করায়।


13
প্রকৃতপক্ষে, সুনির্দিষ্টভাবে বলতে গেলে, মাইএসকিউএল এর প্রতিস্থাপন সর্বদা একটি সন্নিবেশ করায়, তবে এটি সারিটি ইতিমধ্যে উপস্থিত থাকলে, মুছে ফেলবে first dev.mysql.com/doc/refman/4.1/en/replace.html
ইভান

91
এটি বোঝা গুরুত্বপূর্ণ যে এটি একটি সন্নিবেশ + মুছুন এবং কখনই না এবং আপডেট। এর পরিণতি হ'ল আপনি যখন প্রতিস্থাপন করবেন তখন সর্বদা এটি নিশ্চিত করতে চাইবেন, আপনার সব ক্ষেত্রে সমস্ত ক্ষেত্রে ডেটা অন্তর্ভুক্ত করা উচিত।
জোরেডেচে

4
@ জোরদাচে প্রযুক্তিগতভাবে, এটি একটি 'মুছুন, তারপরে সন্নিবেশ করুন', একটি (এন) হিসাবে 'সন্নিবেশ + মুছুন' কার্যকরভাবে মুছে ফেলার মতো তবে এটি চুলের বিভাজন।
এজি হ্যামার্থিফ

4
@ অজিহ্যামার্থিফ একটি খুব বাস্তব পার্থক্য আছে যে সদ্য সন্নিবেশ করা সারিটির মুছে ফেলা সারিটির মতো প্রাথমিক কী থাকবে না। অনুলিপিটি দিয়ে এটি একই প্রাথমিক কী হবে (আপনি নির্দিষ্টভাবে এটি পরিবর্তন না করে)।
টিম স্ট্রিজডহর্স্ট

33

এসকিউএলাইট ইতিমধ্যে উপস্থিত থাকলে একটি সারি প্রতিস্থাপন সমর্থন করে :

INSERT OR REPLACE INTO [...blah...]

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

REPLACE INTO [...blah...]

এই শর্টকাটটি মাইএসকিউএল REPLACE INTOএক্সপ্রেশনের সাথে সামঞ্জস্যপূর্ণ হওয়ার জন্য যুক্ত করা হয়েছিল ।


এটির জন্য PRAMARY KEYআপনার মানগুলিতে একটি সংজ্ঞায়িত করা দরকার ।
ডনসং

25

আমি নিম্নলিখিত মত কিছু করতে হবে:

INSERT INTO cache VALUES (key, generation)
ON DUPLICATE KEY UPDATE (key = key, generation = generation + 1);

কোডে বা স্কেলে প্রজন্মের মান 0 তে সেট করা হচ্ছে তবে মান বাড়ানোর জন্য ডিএনপি ... ব্যবহার করুন। আমি মনে করি এটি যাইহোক সিনট্যাক্স।


4
এই উত্তরটি সত্যই নির্বাচিত উত্তর হওয়া উচিত। আপনি যদি সমস্ত ক্ষেত্র কোনও এন্ট্রিতে জমা না দিয়ে থাকেন তবে এটি একটি অ-ধ্বংসাত্মক সম্পাদনা।
জর্দান

9

অনুলিপি কী আপডেটের ধারাটি সর্বোত্তম সমাধান কারণ: পুনঃস্থাপন একটি সাইন্টের পরে একটি বিলোপ ডিলিট করে যাতে কখনও কখনও সামান্য সময়ের জন্য রেকর্ডটি মুছে ফেলা হয় এমন একদম সামান্য সম্ভাবনা তৈরি করে যে কোনও ক্যোয়ারী ফিরে আসতে পারে যে যদি পৃষ্ঠাটি থাকে তবে REPLACE ক্যোয়ারির সময় দেখা হয়েছে।

আমি সন্নিবেশকে পছন্দ করি ... সেই কারণে ডুপ্লিকেট আপডেটে ...

jmoz এর সমাধানটি সেরা: যদিও আমি প্রথম বন্ধনীগুলির তুলনায় SET বাক্য গঠনটি পছন্দ করি

INSERT INTO cache 
SET key = 'key', generation = 'generation'
ON DUPLICATE KEY 
UPDATE key = 'key', generation = (generation + 1)
;

4
প্রতিস্থাপনটি পারমাণবিক, সুতরাং এমন কোনও সময়সীমা নেই যেখানে সারিটির অস্তিত্ব নেই।
ব্রিলিয়ানড

8

আমি জানি না যে আপনি একটি প্ল্যাটফর্ম-নিরপেক্ষ সমাধান সন্ধান করতে চলেছেন।

একে সাধারণত "ইউপিএসইআরটি" বলা হয়।

সম্পর্কিত কিছু আলোচনা দেখুন:


সমাধান কি আসলেই প্রযোজ্য? এবং বহনযোগ্য?
রায়ান গ্রাহাম

5

পোস্টগ্রেএসকিউএল-তে কোনও মার্জ কমান্ড নেই, এবং আসলে এটি লিপিবদ্ধ নয় - বাস্তবে অদ্ভুত প্রান্তের কেস রয়েছে যা কার্যটিকে "আকর্ষণীয়" করে তোলে।

সেরা (যেমন: সর্বাধিক সম্ভাব্য অবস্থার সাথে কাজ করা) পন্থাটি হ'ল ফাংশনটি ব্যবহার করা - যেমন ম্যানুয়ালটিতে দেখানো (মার্জ_ডিবি)।

আপনি যদি ফাংশনটি ব্যবহার করতে না চান তবে আপনি সাধারণত :

updated = db.execute(UPDATE ... RETURNING 1)
if (!updated)
  db.execute(INSERT...)

কেবল মনে রাখবেন এটি দোষ প্রমাণ নয় এবং শেষ পর্যন্ত এটি ব্যর্থ হবে


4

স্ট্যান্ডার্ড এসকিউএল এই কাজের জন্য মার্জ স্টেটমেন্ট সরবরাহ করে। সমস্ত ডিবিএমএস মার্জ স্টেটমেন্ট সমর্থন করে না।


0

যদি অ্যাটিক্যালি আপডেট বা সন্নিবেশ করার কোনও সাধারণ উপায় আপনার কাছে না থাকে (যেমন, কোনও লেনদেনের মাধ্যমে) তবে আপনি অন্য লকিংয়ের স্কিমে ফ্যালব্যাক করতে পারেন। একটি 0-বাইট ফাইল, সিস্টেম মিটেক্স, নামযুক্ত পাইপ ইত্যাদি ...


0

আপনি কি sertোকানো ট্রিগার ব্যবহার করতে পারেন? যদি এটি ব্যর্থ হয় তবে একটি আপডেট করুন।


ট্রিগার (কমপক্ষে PostgreSQL এ) চলছে যখন কমান্ডটি কাজ করবে। উদাহরণস্বরূপ, বেস কমান্ড ব্যর্থ হলে আপনার ট্রিগার থাকতে পারে না।

0

আপনার জন্য এসকিউএল লেখার একটি লাইব্রেরি ব্যবহার করে আপনি যদি ঠিক থাকেন তবে আপনি উপসেট ব্যবহার করতে পারেন (বর্তমানে কেবল রুবি এবং পাইথন):

Pet.upsert({:name => 'Jerry'}, :breed => 'beagle')
Pet.upsert({:name => 'Jerry'}, :color => 'brown')

এটি MySQL, Postgres এবং SQLite3 জুড়ে কাজ করে।

এটি মাইএসকিউএল এবং পোস্টগ্রিসে একটি সঞ্চিত প্রক্রিয়া বা ব্যবহারকারী-সংজ্ঞায়িত ফাংশন (ইউডিএফ) লিখেছেন। এটি INSERT OR REPLACEএসকিউএল 3 ব্যবহার করে।

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