এসকিউএলাইট - আপসার্ট * ইনসার্ট বা প্রতিস্থাপন নয়


535

http://en.wikipedia.org/wiki/Upsert

এসকিউএল সার্ভারে সঞ্চিত আপডেট সন্নিবেশ করুন

এসকিউএলাইটে এমনটি করার কোনও চতুর উপায় আছে যা আমি ভেবে দেখিনি?

মূলত আমি রেকর্ডটি উপস্থিত থাকলে চারটি কলামের মধ্যে তিনটি আপডেট করতে চাই, যদি এটি না থাকে তবে আমি চতুর্থ কলামের জন্য ডিফল্ট (NUL) মান সহ রেকর্ডটি লিখতে চাই।

আইডি একটি প্রাথমিক কী তাই ইউপিএসআরটি-তে কেবল একটি রেকর্ড থাকবে।

(আমি আপডেট বা স্পষ্টতই INSERT প্রয়োজন কিনা তা নির্ধারণ করার জন্য আমি SELECT এর ওভারহেড এড়াতে চেষ্টা করছি)

পরামর্শ?


টেবিল তৈরির জন্য এসকিউএলসাইটে সিনট্যাক্সটি নিশ্চিত করতে পারছি না। আমি এটি পরীক্ষার জন্য একটি ডেমো তৈরি করি নি, তবে এটি সমর্থিত বলে মনে হচ্ছে না ..

যদি এটি হয় তবে আমার কাছে তিনটি কলাম রয়েছে যাতে এটি দেখতে আসলে দেখতে পাবেন:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    Blob1 BLOB ON CONFLICT REPLACE, 
    Blob2 BLOB ON CONFLICT REPLACE, 
    Blob3 BLOB 
);

তবে প্রথম দুটি ব্লব দ্বন্দ্ব সৃষ্টি করবে না, কেবল আইডি তাই আমি ব্লব 1 এবং ব্লব 2 প্রতিস্থাপন করতে পারি না (পছন্দ অনুযায়ী)


এসকিউএলাইটে আপডেটগুলি যখন বাঁধাই করা তথ্য সম্পূর্ণ লেনদেন হয়, অর্থাত প্রতিটি প্রেরিত সারিটি আপডেট করা আবশ্যক: সেট / বাইন্ড / স্টেপ / চূড়ান্ত বিবরণী INSERT এর विपरीत নয় যা রিসেট ফাংশনটি ব্যবহারের অনুমতি দেয়

স্টেটমেন্ট অবজেক্টের জীবন কিছুটা এরকম হয়:

  1. Sqlite3_prepare_v2 () ব্যবহার করে অবজেক্ট তৈরি করুন
  2. Sqlite3_bind_ ইন্টারফেস ব্যবহার করে প্যারামিটারগুলি হোস্ট করতে মানগুলি বাঁধুন।
  3. Sqlite3_step () এ কল করে এসকিউএল চালান
  4. Sqlite3_reset () ব্যবহার করে বিবৃতিটি রিসেট করুন তারপরে দ্বিতীয় ধাপে ফিরে যান এবং পুনরাবৃত্তি করুন।
  5. Sqlite3_finalize () ব্যবহার করে স্টেটমেন্ট অবজেক্টটি ধ্বংস করুন।

আপডেট আমি অনুমান করছি যে INSERT এর তুলনায় ধীর গতিতে আছে, তবে এটি কী কী নির্বাচনের সাথে প্রাথমিক কী ব্যবহার করে তুলনা করে?

সম্ভবত আমার 4 র্থ কলাম (ব্লব 3) পড়ার জন্য সিলেক্টটি ব্যবহার করা উচিত এবং তারপরে প্রথম 3 টি কলামের জন্য নতুন ডেটা সহ মূল চতুর্থ কলামটি মিশ্রন করে একটি নতুন রেকর্ড লিখতে ব্যবহার করুন?


5
SQLite - UPSERT প্রাপ্তিসাধ্য প্রাক রিলিজে উল্লেখ করুন: sqlite.1065341.n5.nabble.com/...
গৌরব

3
ইউপিএসআরটি এসকিউএলাইটের 3.24.0 সংস্করণে উপলব্ধ
পাবলো_কর্মী

উত্তর:


854

সারণীতে তিনটি কলাম অনুমান করা হচ্ছে: আইডি, NAME, রোল


BAD: এটি আইডি = 1 এর জন্য সমস্ত কলামগুলি নতুন মান সহ সন্নিবেশ বা প্রতিস্থাপন করবে:

INSERT OR REPLACE INTO Employee (id, name, role) 
  VALUES (1, 'John Foo', 'CEO');

BAD: এটি 2 টি কলাম সন্নিবেশ বা প্রতিস্থাপন করবে ... NAME কলামটি নুল বা ডিফল্ট মানকে সেট করা হবে:

INSERT OR REPLACE INTO Employee (id, role) 
  VALUES (1, 'code monkey');

ভাল : এসকিউএলাইটে সংঘাতের ধারাটিতে ইউপিএসআরটি সমর্থন! ইউপিএসআরটি সিনট্যাক্সটি এসকিউএলাইটে 3.24.0 সংস্করণে যুক্ত হয়েছিল!

ইউপিএসআরটি INSERT- র একটি বিশেষ সিনট্যাক্স সংযোজন যা ইনসার্ট একটি স্বতন্ত্রতা সীমাবদ্ধতা লঙ্ঘন করে যদি INSERT কে আপডেট বা কোনও বিকল্প হিসাবে আচরণ করে। ইউপিএসআরটি স্ট্যান্ডার্ড এসকিউএল নয়। এসকিউএলাইটে ইউপিএসআরটি পোস্টগ্র্রেএসকিউএল দ্বারা প্রতিষ্ঠিত বাক্য গঠন অনুসরণ করে।

এখানে চিত্র বর্ণনা লিখুন

ভাল তবে নম্র: এটি কলামগুলির 2 টি আপডেট করবে। যখন আইডি = 1 উপস্থিত থাকে, NAME প্রভাবিত হবে না। যখন আইডি = 1 উপস্থিত নেই, নামটি ডিফল্ট হবে (NULL)।

INSERT OR REPLACE INTO Employee (id, role, name) 
  VALUES (  1, 
            'code monkey',
            (SELECT name FROM Employee WHERE id = 1)
          );

এটি কলামের 2 টি আপডেট করবে। যখন আইডি = 1 বিদ্যমান থাকে, তখন আরওএল প্রভাবিত হবে না। যখন আইডি = 1 বিদ্যমান নেই, তখন ভূমিকাটি ডিফল্ট মানের পরিবর্তে 'বেঞ্চওয়ার্মার' এ সেট করা হবে।

INSERT OR REPLACE INTO Employee (id, name, role) 
  VALUES (  1, 
            'Susan Bar',
            COALESCE((SELECT role FROM Employee WHERE id = 1), 'Benchwarmer')
          );

33
+1 উজ্জ্বল! এম্বেড করা নির্বাচন ক্লজটি আপনাকে যদি কোনও ক্ষেত্রের জন্য পুরানো মান এবং নতুন মানকে একত্রিত / তুলনা করতে হয় তবে কনফ্লিক রিপ্লেস কার্যকারিতা ডিফল্টটিকে ওভাররাইড করার জন্য নমনীয়তা দেয়।
G__

24
যদি কর্মীকে অন্য সারি দ্বারা ক্যাসকেডিং মোছার সাথে উল্লেখ করা হয়, তবে অন্য সারিগুলি প্রতিস্থাপনের মাধ্যমে মুছে ফেলা হবে।
ডন রেবা

246
এটি ব্যাথা করে SQlite এর ইউপিএসআরটি দরকার।
অ্যান্ডিগ

21
আপনি কী ব্যাখ্যা করতে পারবেন যে এটি আইডি = 1 এর জন্য সমস্ত কলামগুলিকে নতুন মান সহ সন্নিবেশ করবে বা প্রতিস্থাপন করবে কেন আপনার প্রথম উদাহরণে বিএডি বিবেচনা করা হয় ? আপনি যে কমান্ডটি উপস্থাপন করছেন তার অর্থ হ'ল আইডি 1 দিয়ে একটি নতুন রেকর্ড তৈরি করা হবে, জন ফু এবং ভূমিকা প্রধান নির্বাহী , বা তথ্যটি ইতিমধ্যে সেখানে রয়েছে, যার আইডি 1 রয়েছে রেকর্ডটি ওভাররাইট করে ( আইডিটি প্রাথমিক কী হিসাবে ধরে নেওয়া) । সুতরাং, কেন ঠিক এমনটি ঘটে যদি খারাপ হয়?
বা ম্যাপার

10
@ কর্নেলিয়াস: এটি পরিষ্কার, তবে প্রথম উদাহরণে যা ঘটে তা তা নয়। প্রথম উদাহরণটি বোঝানো হয়েছে সমস্ত কলামগুলি জোর করে সেট করা, যা ঠিক যা ঘটে তা রেকর্ড সন্নিবেশ করা বা প্রতিস্থাপন করা হয় না কেন। সুতরাং, কেন এটি খারাপ হিসাবে বিবেচনা করা হয়? লিঙ্কযুক্ত উত্তরটি কেবল আপনার দ্বিতীয় উদাহরণের মতো কলামগুলির একটি উপসেট নির্দিষ্ট করার সময় কেন খারাপ কিছু হতে পারে তা উল্লেখ করে ; এটি আপনার প্রথম উদাহরণে যা ঘটে তার কোনও খারাপ প্রভাব সম্পর্কে বিস্তারিত বলে মনে হচ্ছে না , INSERT OR REPLACEযখন সমস্ত কলামের মান উল্লেখ করে ।
অথবা ম্যাপার

134

INSERT or REPLACE "UPSERT" এর সমতুল্য নয়

বলুন যে আমার কাছে ক্ষেত্রের আইডি, নাম এবং ভূমিকা সহ টেবিল কর্মচারী রয়েছে:

INSERT OR REPLACE INTO Employee ("id", "name", "role") VALUES (1, "John Foo", "CEO")
INSERT OR REPLACE INTO Employee ("id", "role") VALUES (1, "code monkey")

বুম, আপনি কর্মচারী নম্বর 1 এর নামটি হারিয়েছেন S এসকিউএলাইট এটি একটি ডিফল্ট মান দিয়ে প্রতিস্থাপন করেছে।

কোনও ইউপিএসআরটির প্রত্যাশিত আউটপুট হ'ল ভূমিকা পরিবর্তন করা এবং নাম রাখা।


21
-1 আমার কাছ থেকে ভয় পাচ্ছি। হ্যাঁ স্বীকৃত উত্তরটি ভুল, তবে আপনার উত্তরটি সমস্যার উল্লেখ করলেও এটি কোনও উত্তর নয়। প্রকৃত উত্তরের জন্য, এম্বেড থাকা ধারাটি ব্যবহার করে এরিক বি এর চতুর সমাধান দেখুনcoalesce((select ..), 'new value') । আমার মনে হয় এরিকের উত্তরের আরও বেশি ভোট দরকার।
দিন

22
প্রকৃতপক্ষে. এরিক অবশ্যই সেরা উত্তর এবং আরও ভোটের দাবিদার। বলা হচ্ছে, আমি মনে করি যে সমস্যাটি চিহ্নিত করে আমি ভাল উত্তরটি খুঁজে পেতে কিছুটা অবদান রেখেছি (এরিকের উত্তর পরে এসেছিল, এবং আমার উত্তরটিতে স্যাম্পল স্ক্যাল টেবিলগুলি তৈরি করে)। সুতরাং আমি নিশ্চিত নই যে আমি -1 প্রাপ্য কিনা, তবে কোনও বিষয় নয় :)
গ্রেগস্লোম

6
উপরে -1 অফসেট করতে +1। হাঃ হাঃ হাঃ. যদিও এই থ্রেডে আকর্ষণীয় টাইমলাইন। স্পষ্টতই আপনার উত্তর এরিকের এক সপ্তাহ আগে শেষ হয়েছিল, তবে আপনি উভয়ই প্রশ্নের উত্তর জিজ্ঞাসা করার প্রায় দুই বছর পরে উত্তর দিয়েছিলেন। এরিকের জন্যও +1 বিস্তৃত করার জন্য যদিও।
ধনী


2
@ কিউড না, কারণ মুছুন + সন্নিবেশ (যা প্রতিস্থাপন) 2 ডিএমএল স্টেটমেন্ট, উদাহরণস্বরূপ তাদের নিজস্ব ট্রিগার সহ। এটি কেবলমাত্র 1 আপডেটের স্টেটমেন্টের মতো নয়।
সেবাসস

109

আপনি যদি বিদ্যমান সারি থেকে কেবল একটি বা সম্ভবত দুটি কলাম সংরক্ষণ করতে চান তবে এরিক বি এর উত্তর ঠিক আছে। আপনি যদি অনেকগুলি কলাম সংরক্ষণ করতে চান তবে এটি খুব জটিল gets

এখানে এমন একটি দৃষ্টিভঙ্গি রয়েছে যা উভয় পক্ষের যে কোনও পরিমাণ কলামকে ভাল স্কেল করবে। এটি চিত্রিত করার জন্য আমি নিম্নলিখিত স্কিমাটি ধরে নেব:

 CREATE TABLE page (
     id      INTEGER PRIMARY KEY,
     name    TEXT UNIQUE,
     title   TEXT,
     content TEXT,
     author  INTEGER NOT NULL REFERENCES user (id),
     ts      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 );

nameসারিটির প্রাকৃতিক কীটি বিশেষত দ্রষ্টব্য - idকেবল বিদেশী কীগুলির জন্য ব্যবহৃত হয়, সুতরাং কোনও নতুন সারি সন্নিবেশ করানোর সময় এসকিউএলাইটের আইডি মানটি নিজেই বাছাই করা উচিত। তবে এর উপর ভিত্তি করে কোনও বিদ্যমান সারি আপডেট করার সময় name, আমি এটির পুরানো আইডি মানটি অবিরত রাখতে চাই (স্পষ্টতই!)।

আমি UPSERTনিম্নলিখিত নির্মাণের সাথে একটি সত্য অর্জন করেছি :

 WITH new (name, title, author) AS ( VALUES('about', 'About this site', 42) )
 INSERT OR REPLACE INTO page (id, name, title, content, author)
 SELECT old.id, new.name, new.title, old.content, new.author
 FROM new LEFT JOIN page AS old ON new.name = old.name;

এই ক্যোয়ারির সঠিক ফর্মটি কিছুটা আলাদা হতে পারে। কীটি হ'ল INSERT SELECTনতুন মানগুলিতে একটি বিদ্যমান সারিটিতে যোগদানের জন্য বাম বাহ্যিক জোড় যুক্ত ব্যবহার ।

এখানে, যদি কোনও সারি আগে উপস্থিত না থাকে তবে old.idতা হবে NULLএবং এসকিউএলাইট স্বয়ংক্রিয়ভাবে একটি আইডি নির্ধারণ করবে, তবে ইতিমধ্যে যদি এই জাতীয় সারি old.idথাকে তবে একটি আসল মান থাকবে এবং এটি পুনরায় ব্যবহৃত হবে। যা আমি চেয়েছিলাম ঠিক তাই।

আসলে এটি খুব নমনীয়। tsকলামটি সমস্ত দিক থেকে কীভাবে পুরোপুরি অনুপস্থিত তা নোট করুন - কারণ এর একটি DEFAULTমান রয়েছে, এসকিউএলাইট যে কোনও ক্ষেত্রে ঠিক সঠিক কাজটি করবে, সুতরাং আমাকে এটি নিজেই যত্ন নিতে হবে না।

আপনি উভয় newএবং উভয় পক্ষেই একটি কলাম অন্তর্ভুক্ত করতে পারেন oldএবং তারপরে COALESCE(new.content, old.content)বাইরের মধ্যে SELECT"নতুন সামগ্রীটি যদি থাকে তবে সন্নিবেশ করান, অন্যথায় পুরানো সামগ্রীটি রাখুন" বলার জন্য ব্যবহার করতে পারেন - উদাহরণস্বরূপ যদি আপনি একটি স্থির ক্যোয়ারী ব্যবহার করছেন এবং নতুনকে আবদ্ধ করছেন স্থানধারক সহ মান।


13
+1, দুর্দান্ত কাজ WHERE name = "about"করে তবে SELECT ... AS oldজিনিসগুলিকে গতি বাড়ানোর ক্ষেত্রে একটি সীমাবদ্ধতা যুক্ত করুন । আপনার যদি 1 মি + সারি থাকে তবে এটি খুব ধীর।

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

4
আপনি চাইলে এরিস্টটলের উদাহরণটি এটিকে সহজ করতে পারেন: INSERT OR REPLACE INTO page (id, name, title, content, author) SELECT id, 'about', 'About this site', content, 42 FROM ( SELECT NULL ) LEFT JOIN ( SELECT * FROM page WHERE name = 'about' )
jcox

4
ON DELETEযখন এটি প্রতিস্থাপন (যা একটি আপডেট) সম্পাদন করে তবে অযৌক্তিকভাবে ট্রিগারগুলি ট্রিগার করবে না ?
করাকুড়ি

3
এটি অবশ্যই ON DELETEট্রিগারগুলি ট্রিগার করবে । অকারণে ডুনো। বেশিরভাগ ব্যবহারকারীর জন্য এটি সম্ভবত অপ্রয়োজনীয় এমনকি অযাচিত হতে পারে তবে সমস্ত ব্যবহারকারীর পক্ষেও তা সম্ভবত নয়। একইভাবে এটি যে প্রশ্নে সারিটিতে বিদেশী কীগুলি সহ যে কোনও সারিকে ক্যাসকেড-মুছে ফেলবে - সম্ভবত অনেক ব্যবহারকারীর জন্যই এটি একটি সমস্যা। দুর্ভাগ্যক্রমে, এসকিউএলাইটের সত্যিকারের ইউপিএসআরটির খুব কাছাকাছি কিছু নেই। (এটি একটি INSTEAD OF UPDATEট্রিগার দিয়ে
নকল করার

86

আপনি যদি সাধারণত আপডেটগুলি করেন তবে আমি করতাম ..

  1. একটি লেনদেন শুরু করুন
  2. আপডেট করুন
  3. সারি গণনা পরীক্ষা করুন
  4. যদি 0 হয় তবে সন্নিবেশ করান
  5. সমর্পণ করা

আপনি যদি সাধারণত ইনসার্টগুলি করেন তবে আমি করব

  1. একটি লেনদেন শুরু করুন
  2. একটি সন্নিবেশ চেষ্টা করুন
  3. প্রাথমিক কী লঙ্ঘনের ত্রুটিটি পরীক্ষা করুন
  4. আমাদের যদি ত্রুটি হয় তবে আপডেটটি করুন
  5. সমর্পণ করা

এইভাবে আপনি নির্বাচনটি এড়িয়ে যাবেন এবং আপনি স্ক্লাইটে লেনদেনের মতো শব্দ করছেন।


ধন্যবাদ, কেবল এই @ স্ট্যাকওভারফ্লো . com/ জিজ্ঞাসা / 2717590/… জিজ্ঞাসা করেছেন । আমার কাছ থেকে +1! =)
অ্যালিক্স অ্যাক্সেল

4
আপনি যদি তৃতীয় ধাপে sqlite3_changes () ব্যবহার করে সারি হিসাব পরীক্ষা করতে যাচ্ছেন তবে নিশ্চিত হয়ে নিন যে আপনি সংশোধনের জন্য একাধিক থ্রেড থেকে ডিবি হ্যান্ডেল ব্যবহার করছেন না।
লিনুলিন

3
নীচে একই প্রভাব সহ এখনও কম শব্দযুক্ত হবে না: 1) আইডি ফর্ম টেবিল নির্বাচন করুন যেখানে id = 'x' 2) যদি (রেজাল্টসেট.আরওয়েথ == 0) আপডেট টেবিল যেখানে id = 'x';
ফ্লোরিন

20
আমি সত্যিই ইচ্ছে করি INSERT বা আপডেট হওয়া ভাষাটির অংশ ছিল
ফ্লোরিন

এটি আমার পক্ষে সবচেয়ে ভাল কাজ করে শেষ হয়েছে, সর্বদা প্রতিস্থাপন করার চেষ্টা করে বা সর্বদা সন্নিবেশ করা / আপডেট করা আমার সম্পাদনটিকে হত্যা করে যখন আমি প্রাথমিকভাবে সন্নিবেশের পরিবর্তে আপডেটগুলি করি।
PherricOxide

83

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

2018-05-18 স্টপ প্রেস।

এসকিউএলটিতে ইউপিএসআরটি সমর্থন! ইউপিএসআরটি সিনট্যাক্সটি এসকিউএলাইটে 3.24.0 সংস্করণ যুক্ত করা হয়েছে (মুলতুবি)!

ইউপিএসআরটি INSERT- র একটি বিশেষ সিনট্যাক্স সংযোজন যা ইনসার্ট একটি স্বতন্ত্রতা সীমাবদ্ধতা লঙ্ঘন করে যদি INSERT কে আপডেট বা কোনও বিকল্প হিসাবে আচরণ করে। ইউপিএসআরটি স্ট্যান্ডার্ড এসকিউএল নয়। এসকিউএলাইটে ইউপিএসআরটি পোস্টগ্র্রেএসকিউএল দ্বারা প্রতিষ্ঠিত বাক্য গঠন অনুসরণ করে।

এখানে চিত্র বর্ণনা লিখুন

অন্যথায়:

এটি করার আরেকটি সম্পূর্ণ ভিন্ন উপায় হ'ল: আমার অ্যাপ্লিকেশনটিতে আমি আমার মেমরিটিতে সারিটি দীর্ঘ রাখি। ম্যাক্সভ্যালু যখন আমি মেমরিতে সারি তৈরি করি। (ম্যাক্সভ্যালু কখনই আইডি হিসাবে ব্যবহৃত হবে না আপনি বেশি দিন বাঁচবেন না .... তারপরে যদি রোআইডিআইডিটি মান না হয় তবে এটি অবশ্যই ডেটাবেজে থাকতে হবে তাই এটি যদি ম্যাক্সভ্যালু হয় তবে একটি আপডেট প্রয়োজন then এটি কেবলমাত্র তখনই কার্যকর যখন আপনি নিজের অ্যাপ্লিকেশনটিতে রোডআইডিগুলি ট্র্যাক করতে পারেন।


5
আমেন। সহজ জটিল চেয়ে ভাল। এটি গৃহীত উত্তরের চেয়ে কিছুটা সহজ বোধ করে।
কুকুরিয়ান

4
আমি ভেবেছিলাম আপনি ভিতরে প্রবেশ করতে পারবেন না ... কোথায় স্ক্লাইটে? এটি স্ক্লাইট 3 এ আমার জন্য একটি সিনট্যাক্স ত্রুটি
চার্লি মার্টিন

5
@ চার্লিমার্টিন সঠিক এই বাক্য গঠনটি এসকিউএলাইটের জন্য অবৈধ - যা ওপি অনুরোধ করেছিল। WHEREএকটি INSERTবিবৃতিতে একটি ধারা যুক্ত করা যাবে না : স্ক্লাইট-সন্নিবেশ ...
কলম.আনসেও

4
এই উত্তরটি আমাকে অনেক সময় looseিলে করে
মিকেল

3
@ কলিনেটর এবং অন্যান্য: আপনার পরামর্শটি ব্যবহার করে আমি তার এসকিউএল বিবৃতি স্থির করেছি।
এফ লেকচাস

61

আমি বুঝতে পারি এটি একটি পুরানো থ্রেড তবে আমি স্কেলাইট 3 এ দেরিতে কাজ করছি এবং এই পদ্ধতিটি নিয়ে এসেছি যা আমার প্যারামিটারাইজড কোয়েরিগুলি উত্পন্ন করার জন্য আমার প্রয়োজনের সাথে আরও উপযুক্ত করে:

insert or ignore into <table>(<primaryKey>, <column1>, <column2>, ...) values(<primaryKeyValue>, <value1>, <value2>, ...); 
update <table> set <column1>=<value1>, <column2>=<value2>, ... where changes()=0 and <primaryKey>=<primaryKeyValue>; 

এটি এখনও 2 টি ক্যোয়ারী রয়েছে যেখানে আপডেটটিতে ধারা রয়েছে তবে মনে হয় কৌতুকটি করছে। আমার মাথায়ও এই দৃষ্টি রয়েছে যে স্ক্লাইটটি আপডেট স্টেটমেন্টটিকে পুরোপুরি অপ্টিমাইজ করতে পারে যদি কলগুলিতে পরিবর্তন () পরিবর্তন শূন্যের চেয়ে বেশি হয়। এটি আসলে আমার জ্ঞানের বাইরে যা আছে কি না, তবে কোনও মানুষ কি সে স্বপ্ন দেখতে পারে? ;)

বোনাস পয়েন্টের জন্য আপনি এই লাইনটি সংযুক্ত করতে পারেন যা সারিটির আইডি ফিরিয়ে দেয় এটি সদ্য প্রবেশ করানো সারি বা বিদ্যমান সারি।

select case changes() WHEN 0 THEN last_insert_rowid() else <primaryKeyValue> end;

+ ১. কিছু এসকিউএল সার্ভার টিএসকিউএল কোড থেকে রূপান্তরকরণটি বদলে আমি ঠিক কী চেষ্টা করছিলাম। ধন্যবাদ। এসকিউএল আমি প্রতিস্থাপনের চেষ্টা করছিলাম যা ছিলUpdate <statement> If @@ROWCOUNT=0 INSERT INTO <statement>
ড্যারেনএমবি

14

এখানে এমন একটি সমাধান দেওয়া হয়েছে যা প্রকৃতপক্ষে কোনও INSERT বা REPLACE (যা অনেক পরিস্থিতিতে আলাদাভাবে কাজ করে) এর পরিবর্তে একটি UPSERT (আপডেট বা INSERT)।

এটি এর মতো কাজ করে:
১. একই আইডির সাথে কোনও রেকর্ড উপস্থিত থাকলে আপডেট করার চেষ্টা করুন।
২. আপডেটটি যদি কোনও সারি ( NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0)) পরিবর্তন না করে তবে রেকর্ডটি .োকান।

সুতরাং হয় একটি বিদ্যমান রেকর্ড আপডেট হয়েছে বা একটি সন্নিবেশ সম্পাদন করা হবে।

গুরুত্বপূর্ণ বিবরণটি হ'ল পরিবর্তনগুলি () এসকিউএল ফাংশনটি ব্যবহার করে আপডেট স্টেটমেন্টটি কোনও বিদ্যমান রেকর্ডকে আঘাত করে কিনা তা পরীক্ষা করে দেখানো এবং এটি কোনও রেকর্ড না আঘাত করলে কেবল সন্নিবেশ বিবৃতিটি সম্পাদন করে।

একটি বিষয় উল্লেখ করার জন্য হ'ল পরিবর্তনগুলি () ফাংশনটি নিম্ন-স্তরের ট্রিগারগুলির দ্বারা সম্পাদিত পরিবর্তনগুলি ফিরে আসে না (দেখুন http://sqlite.org/lang_corefunc.html# পরিবর্তনসমূহ ), তাই এটিকে অ্যাকাউন্টে নেওয়ার বিষয়টি নিশ্চিত হন।

এখানে এসকিউএল ...

পরীক্ষার আপডেট:

--Create sample table and records (and drop the table if it already exists)
DROP TABLE IF EXISTS Contact;
CREATE TABLE [Contact] (
  [Id] INTEGER PRIMARY KEY, 
  [Name] TEXT
);
INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
INSERT INTO Contact (Id, Name) VALUES (2, 'John');

-- Try to update an existing record
UPDATE Contact
SET Name = 'Bob'
WHERE Id = 2;

-- If no record was changed by the update (meaning no record with the same Id existed), insert the record
INSERT INTO Contact (Id, Name)
SELECT 2, 'Bob'
WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);

--See the result
SELECT * FROM Contact;

পরীক্ষার সন্নিবেশ:

--Create sample table and records (and drop the table if it already exists)
DROP TABLE IF EXISTS Contact;
CREATE TABLE [Contact] (
  [Id] INTEGER PRIMARY KEY, 
  [Name] TEXT
);
INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
INSERT INTO Contact (Id, Name) VALUES (2, 'John');

-- Try to update an existing record
UPDATE Contact
SET Name = 'Bob'
WHERE Id = 3;

-- If no record was changed by the update (meaning no record with the same Id existed), insert the record
INSERT INTO Contact (Id, Name)
SELECT 3, 'Bob'
WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);

--See the result
SELECT * FROM Contact;

2
এটি আমার কাছে এরিকের চেয়ে ভাল সমাধান বলে মনে হচ্ছে। তবে INSERT INTO Contact (Id, Name) SELECT 3, 'Bob' WHERE changes() = 0;কাজ করা উচিত।
bkausbk

আপনাকে ধন্যবাদ মানুষ, এটি
ওয়েবএসকিউএলে

11

সংস্করণ ৩.২৪.০. দিয়ে শুরু করা ইউপিএসআরটি এসকিউএলাইট দ্বারা সমর্থিত।

ডকুমেন্টেশন থেকে :

ইউপিএসআরটি INSERT- র একটি বিশেষ সিনট্যাক্স সংযোজন যা ইনসার্ট একটি স্বতন্ত্রতা সীমাবদ্ধতা লঙ্ঘন করে যদি INSERT কে আপডেট বা কোনও বিকল্প হিসাবে আচরণ করে। ইউপিএসআরটি স্ট্যান্ডার্ড এসকিউএল নয়। এসকিউএলাইটে ইউপিএসআরটি পোস্টগ্র্রেএসকিউএল দ্বারা প্রতিষ্ঠিত বাক্য গঠন অনুসরণ করে। ইউপিএসআরটি সিনট্যাক্সটি এসকিউএলাইটে 3.24.0 সংস্করণ (মুলতুবি) সহ যুক্ত করা হয়েছিল।

একটি ইউপিএসআরটি হ'ল একটি সাধারণ ইনসার্ট স্টেটমেন্ট যা তারপরে ওএন কনফ্লিক্ট ধারাটি অনুসরণ করে

এখানে চিত্র বর্ণনা লিখুন

চিত্র উত্স: https://www.sqlite.org/images/syntax/upsert-clause.gif


8

আপনি সত্যই এসকিউএলাইটে একটি উপস্থাপনা করতে পারেন, এটি আপনার ব্যবহারের চেয়ে একটু আলাদা দেখাচ্ছে। এটি দেখতে কিছু হবে:

INSERT INTO table name (column1, column2) 
VALUES ("value12", "value2") WHERE id = 123 
ON CONFLICT DO UPDATE 
SET column1 = "value1", column2 = "value2" WHERE id = 123

5

অ্যারিস্টটলের উত্তরে প্রসারিত হচ্ছে আপনি একটি ডামি 'সিঙ্গেলটন' টেবিল (একক সারিতে আপনার নিজস্ব তৈরির একটি টেবিল) থেকে নির্বাচন করতে পারেন। এটি কিছু অনুলিপি এড়ানো।

আমি মাইএসকিউএল এবং এসকিউএলাইট জুড়ে পোর্টেবল উদাহরণও রেখেছি এবং আপনি কীভাবে প্রথমবার প্রথমবার কলাম সেট করতে পারবেন তার উদাহরণ হিসাবে একটি 'ডেট_ড্যাড' কলামটি ব্যবহার করেছি।

 REPLACE INTO page (
   id,
   name,
   title,
   content,
   author,
   date_added)
 SELECT
   old.id,
   "about",
   "About this site",
   old.content,
   42,
   IFNULL(old.date_added,"21/05/2013")
 FROM singleton
 LEFT JOIN page AS old ON old.name = "about";

4

আমি জানি সবচেয়ে ভাল পদ্ধতির একটি আপডেট করা হয়, তার পরে একটি inোকানো হয়। "একটি নির্বাচনের ওভারহেড" প্রয়োজনীয়, তবে আপনি প্রাথমিক কীটি অনুসন্ধান করছেন যেহেতু এটি তীব্র বোঝা নয় which

আপনি যা চান তা করতে আপনার টেবিল এবং ফিল্ডের নামগুলি সহ নীচের বিবৃতিগুলি পরিবর্তন করতে সক্ষম হওয়া উচিত।

--first, update any matches
UPDATE DESTINATION_TABLE DT
SET
  MY_FIELD1 = (
              SELECT MY_FIELD1
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
 ,MY_FIELD2 = (
              SELECT MY_FIELD2
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
WHERE EXISTS(
            SELECT ST2.PRIMARY_KEY
            FROM
              SOURCE_TABLE ST2
             ,DESTINATION_TABLE DT2
            WHERE ST2.PRIMARY_KEY = DT2.PRIMARY_KEY
            );

--second, insert any non-matches
INSERT INTO DESTINATION_TABLE(
  MY_FIELD1
 ,MY_FIELD2
)
SELECT
  ST.MY_FIELD1
 ,NULL AS MY_FIELD2  --insert NULL into this field
FROM
  SOURCE_TABLE ST
WHERE NOT EXISTS(
                SELECT DT2.PRIMARY_KEY
                FROM DESTINATION_TABLE DT2
                WHERE DT2.PRIMARY_KEY = ST.PRIMARY_KEY
                );

7
জটিল উপায়।
ফ্রেস্ট

আমি মনে করি এটি একটি ভাল ধারণা নয় কারণ আপনাকে ডাটাবেস ইঞ্জিনে দুবার অনুরোধ করতে হবে।
রিকার্ডো দা রোচা ভাইটার

3

যদি কেউ কর্ডোভাতে এসকিউএলাইটের জন্য আমার সমাধানটি পড়তে চান তবে উপরের ডেভিড উত্তরের জন্য আমি এই জেনেরিক জেএস পদ্ধতিটি পেয়েছি।

function    addOrUpdateRecords(tableName, values, callback) {
get_columnNames(tableName, function (data) {
    var columnNames = data;
    myDb.transaction(function (transaction) {
        var query_update = "";
        var query_insert = "";
        var update_string = "UPDATE " + tableName + " SET ";
        var insert_string = "INSERT INTO " + tableName + " SELECT ";
        myDb.transaction(function (transaction) {
            // Data from the array [[data1, ... datan],[()],[()]...]:
            $.each(values, function (index1, value1) {
                var sel_str = "";
                var upd_str = "";
                var remoteid = "";
                $.each(value1, function (index2, value2) {
                    if (index2 == 0) remoteid = value2;
                    upd_str = upd_str + columnNames[index2] + "='" + value2 + "', ";
                    sel_str = sel_str + "'" + value2 + "', ";
                });
                sel_str = sel_str.substr(0, sel_str.length - 2);
                sel_str = sel_str + " WHERE NOT EXISTS(SELECT changes() AS change FROM "+tableName+" WHERE change <> 0);";
                upd_str = upd_str.substr(0, upd_str.length - 2);
                upd_str = upd_str + " WHERE remoteid = '" + remoteid + "';";                    
                query_update = update_string + upd_str;
                query_insert = insert_string + sel_str;  
                // Start transaction:
                transaction.executeSql(query_update);
                transaction.executeSql(query_insert);                    
            });
        }, function (error) {
            callback("Error: " + error);
        }, function () {
            callback("Success");
        });
    });
});
}

সুতরাং, প্রথমে এই ফাংশনটির সাথে কলামের নামগুলি বেছে নিন:

function get_columnNames(tableName, callback) {
myDb.transaction(function (transaction) {
    var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
    transaction.executeSql(query_exec, [], function (tx, results) {
        var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
        var columnNames = [];
        for (i in columnParts) {
            if (typeof columnParts[i] === 'string')
                columnNames.push(columnParts[i].split(" ")[0]);
        };
        callback(columnNames);
    });
});
}

তারপরে প্রোগ্রামগুলি লেনদেনগুলি তৈরি করুন।

"মানগুলি" এমন একটি অ্যারে যা আপনার আগে তৈরি করা উচিত এবং এটি সারণীতে সন্নিবেশ করানো বা আপডেট করতে চান এমন সারিগুলি উপস্থাপন করে।

"রিমোটিড" হ'ল আইডিটি আমি উল্লেখ হিসাবে ব্যবহার করেছি, যেহেতু আমি আমার দূরবর্তী সার্ভারের সাথে সিঙ্ক করছি।

SQLite কর্ডোভা প্লাগইন ব্যবহারের জন্য দয়া করে অফিসিয়াল লিঙ্কটি দেখুন


2

এই পদ্ধতিটি এই প্রশ্নের উত্তর থেকে অন্যান্য কয়েকটি পদ্ধতির পুনরায় সাদৃশ্য করে এবং সিটিই (প্রচলিত সারণী এক্সপ্রেশন) এর ব্যবহারকে অন্তর্ভুক্ত করে। আমি ক্যোয়ারির সাথে পরিচয় করিয়ে দেব তারপর আমি কেন করেছি তা ব্যাখ্যা করব।

আমি যদি কোনও কর্মচারী 300 থাকে তবে আমি 300 কর্মচারীর শেষ নামটি ডেভিস-এ পরিবর্তন করতে চাই Otherwise নইলে আমি একটি নতুন কর্মী যুক্ত করব।

সারণীর নাম: কর্মচারী কলাম: আইডি, প্রথম নাম, শেষ নাম name

প্রশ্নটি হ'ল:

INSERT OR REPLACE INTO employees (employee_id, first_name, last_name)
WITH registered_employees AS ( --CTE for checking if the row exists or not
    SELECT --this is needed to ensure that the null row comes second
        *
    FROM (
        SELECT --an existing row
            *
        FROM
            employees
        WHERE
            employee_id = '300'

        UNION

        SELECT --a dummy row if the original cannot be found
            NULL AS employee_id,
            NULL AS first_name,
            NULL AS last_name
    )
    ORDER BY
        employee_id IS NULL --we want nulls to be last
    LIMIT 1 --we only want one row from this statement
)
SELECT --this is where you provide defaults for what you would like to insert
    registered_employees.employee_id, --if this is null the SQLite default will be used
    COALESCE(registered_employees.first_name, 'SALLY'),
    'DAVIS'
FROM
    registered_employees
;

মূলত, আমি সিটিই ব্যবহার করে ডিফল্ট মান নির্ধারণের জন্য নির্বাচিত বিবৃতিটি যে বার ব্যবহার করতে হয় তার সংখ্যা হ্রাস করতে। যেহেতু এটি একটি সিটিই, আমরা কেবল সারণী থেকে আমাদের পছন্দসই কলামগুলি নির্বাচন করি এবং INSERT বিবৃতি এটি ব্যবহার করে।

মানগুলি কী হওয়া উচিত তা দিয়ে COALESCE ফাংশনে নালগুলি প্রতিস্থাপন করে আপনি কোন ডিফল্টগুলি ব্যবহার করতে চান তা এখন আপনি সিদ্ধান্ত নিতে পারেন।


2

অ্যারিস্টটল পাগাল্টজিস এবং এরিক বি এর উত্তরCOALESCE থেকে ধারণা অনুসরণ করে , এটি কেবলমাত্র কয়েকটি কলাম আপডেট করতে বা এটি উপস্থিত না থাকলে সম্পূর্ণ সারি সন্নিবেশ করানোর একটি বিকল্প বিকল্প।

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

উল্লেখ্য id যখন শূন্য হতে বাধ্য হয় INSERTযেমন autoincrement হতে অনুমিত হয়। যদি এটি কেবল উত্পন্ন প্রাথমিক কী হয় তবে COALESCEএটিও ব্যবহার করা যেতে পারে ( অ্যারিস্টটল পাগাল্টজির মন্তব্য দেখুন )।

WITH new (id, name, title, content, author)
     AS ( VALUES(100, 'about', 'About this site', 'Whatever new content here', 42) )
INSERT OR REPLACE INTO page (id, name, title, content, author)
SELECT
     old.id, COALESCE(old.name, new.name),
     new.title, new.content,
     COALESCE(old.author, new.author)
FROM new LEFT JOIN page AS old ON new.name = old.name;

সুতরাং সাধারণ নিয়মটি হ'ল, আপনি যদি পুরানো মান রাখতে চান, ব্যবহার করুন COALESCE, যখন আপনি মানগুলি আপডেট করতে চান, ব্যবহার করুনnew.fieldname


COALESCE(old.id, new.id)একটি স্বতঃসংশোধক কী দিয়ে অবশ্যই ভুল। এবং যখন "সারিগুলির বেশিরভাগ সীমা অপরিবর্তিত রাখুন, যেখানে মানগুলি অনুপস্থিত রয়েছে" ব্যতীত কারও কাছে যেমন ব্যবহারের কেস দেখা যায়, তখন আমি মনে করি না যে লোকেরা যখন কোনও ইউপিএসআরটি কীভাবে করবেন তা সন্ধান করছেন।
এরিস্টটল পাগাল্টজিস

@ অ্যারিস্টটল পেগাল্টজিস ক্ষমা চাইলে আমি ভুল হলে আমি স্বতঃআগ্রহ ব্যবহার করি না। আমি এই কোয়েরির সাথে যা খুঁজছি তা হ'ল কেবল কয়েকটি কলস আপডেট করা বা এটি বিদ্যমান না থাকলে সরবরাহিত মান সহ পুরো সারি সন্নিবেশ করানো । আমি আপনার প্রশ্নের সঙ্গে বাজানো করছি এবং ঢোকাতে আমি এটা অর্জন করতে পারি নি: থেকে নির্বাচিত কলাম oldটেবিল যেখানে নির্ধারিত NULL, মানের মধ্যে সরবরাহকৃত না new। এটি ব্যবহারের কারণ COALESCE। আমি স্ক্লাইটে বিশেষজ্ঞ নই, আমি এই ক্যোয়ারীটি পরীক্ষা করে দেখছি এবং এই মামলার জন্য কাজ করছে বলে মনে হচ্ছে, আপনি যদি আমাকে স্বতঃসংশোধনের সাথে সমাধানের দিকে ইঙ্গিত করতে পারেন তবে আমি আপনাকে অনেক ধন্যবাদ জানাব
মিকেল

2
একটি স্বতঃসংশোধক কী এর ক্ষেত্রে, আপনি কী হিসাবে সন্নিবেশ করতে চানNULL , কারণ এটি এসকিউএলাইটকে পরিবর্তে পরবর্তী উপলব্ধ মান সন্নিবেশ করতে বলে।
এরিস্টটল পাগাল্টজিস

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

1

আমি মনে করি এটি আপনি যা খুঁজছেন তা হতে পারে: কনফ্লিক্ট ধারাটিতে

আপনি যদি আপনার টেবিলটিকে এভাবে নির্দিষ্ট করে থাকেন:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    field1 TEXT 
); 

এখন, আপনি যদি ইতিমধ্যে বিদ্যমান আইডি দিয়ে একটি INSERT করেন তবে এসকিউএলাইট স্বয়ংক্রিয়ভাবে INSERT এর পরিবর্তে আপডেট করে।

HTH ...


6
আমি মনে করি এটি কাজ করে না, এটি সন্নিবেশ বিবৃতিটি থেকে অনুপস্থিত কলামগুলি মুছে ফেলবে
স্যাম জাফরন

3
@ মসর: -আমার কাছ থেকে, দুঃখিত। এটি REPLACEবিবৃতি জারি করার সমান ।
অ্যালিক্স অ্যাক্সেল

7
-1 কারণ এটি একটি মুছুন এবং তারপরে প্রাথমিক কীটি ইতিমধ্যে উপস্থিত থাকলে একটি সন্নিবেশ করায়।
ফ্রেস্ট

0

আপনি যদি দুটি অপারেশনে এটি করতে আপত্তি করেন না।

পদক্ষেপ:

1) "INSERT or IGNORE" দিয়ে নতুন আইটেম যুক্ত করুন

2) বিদ্যমান আপডেটগুলি "আপডেট" দিয়ে আপডেট করুন

উভয় পদক্ষেপের ইনপুটটি নতুন বা আপডেট-সক্ষম আইটেমগুলির একই সংগ্রহ collection বিদ্যমান আইটেমগুলির সাথে সূক্ষ্মভাবে কাজ করে যার কোনও পরিবর্তন দরকার নেই। সেগুলি আপডেট করা হবে তবে একই ডেটা এবং সেইজন্য নেট ফলাফলের কোনও পরিবর্তন নেই।

অবশ্যই, ধীর ইত্যাদি। অপর্যাপ্ত। হাঁ।

বর্গ লিখতে এবং এটি বজায় রাখা এবং বুঝতে সহজ? স্পষ্টভাবে.

এটি বিবেচনা করার মতো বাণিজ্য। ছোট আপসার্টের জন্য দুর্দান্ত কাজ করে। কোড রক্ষণাবেক্ষণের জন্য দক্ষতা ত্যাগ করতে কিছু মনে করেন না তাদের পক্ষে দুর্দান্ত কাজ করে।


প্রত্যেককে নোট করুন: অন্তর্ভুক্ত বা প্রতিস্থাপন পোস্টটি কী তা নয়। INSERT or REPLACE আপনার টেবিলে একটি নতুন আইডি সহ একটি নতুন সারি তৈরি করবে। এটি কোনও আপডেট নয়।
স্যাপবকেট

-2

এই থ্রেডটি সবেমাত্র পড়ে এবং হতাশ হয়ে পড়েছেন যে কেবল এই "ইউপিএসআরটি" -র পক্ষে সহজ ছিল না, আমি আরও তদন্ত করেছি ...

আপনি এসকিউএলআইটি এ এটি সরাসরি এবং সহজেই করতে পারেন।

পরিবর্তে ব্যবহার করুন: INSERT INTO

ব্যবহার করুন: INSERT OR REPLACE INTO

এটি আপনি যা করতে চান ঠিক তা করে!


21
-1 INSERT OR REPLACEএকটি নয় UPSERT। যে কারণে গ্র্যাশক্লমের "উত্তর" দেখুন । এরিক বি এর সমাধানটি আসলে কাজ করে এবং এর জন্য কিছু উন্নতি প্রয়োজন।
দিন

-4
SELECT COUNT(*) FROM table1 WHERE id = 1;

যদি COUNT(*) = 0

INSERT INTO table1(col1, col2, cole) VALUES(var1,var2,var3);

অন্যথায় যদি COUNT(*) > 0

UPDATE table1 SET col1 = var4, col2 = var5, col3 = var6 WHERE id = 1;

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