tutorial - w3schools sql




এসকিউএলাইট-ইউপিএসআরটি*না*প্রবেশ করুন বা প্রতিস্থাপন করুন (12)

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

এসকিউএল সার্ভারে সংরক্ষিত প্রসেস আপডেট করুন

আমি SQLite মধ্যে এই কাজ করার কিছু চতুর উপায় যে আমি চিন্তা না?

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

আইডি একটি প্রাথমিক চাবি তাই ইউপিএসইআরটিতে শুধুমাত্র একটি রেকর্ড থাকবে।

(আমি আপডেট বা ইনসার্ট অবশ্যই প্রয়োজন কিনা তা নির্ধারণ করার জন্য SELECT এর ঊর্ধ্বমুখী এড়াতে চেষ্টা করছি)

পরামর্শ?

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

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

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 () ব্যবহার করে বিবৃতিটি রিসেট করুন তারপর ধাপ 2 এ ফিরে যান এবং পুনরাবৃত্তি করুন।
  5. Sqlite3_finalize () ব্যবহার করে বিবৃতি বস্তুটি নষ্ট করুন।

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

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


সংস্করণ 3.24.0 UPSERT দিয়ে শুরু হচ্ছে SQLite দ্বারা সমর্থিত।

documentation থেকে:

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

একটি UPSERT একটি সাধারণ INSERT বিবৃতি যা বিশেষ অন কনফ্লিক্ট বিভাগ দ্বারা অনুসরণ করা হয়

ছবির উৎস:


INSERT বা 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. SQLite এটি একটি ডিফল্ট মান দিয়ে প্রতিস্থাপিত হয়েছে।

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


আমি জানি সর্বোত্তম পদ্ধতি একটি সন্নিবেশ অনুসরণ করে একটি আপডেট করতে হয়। "একটি নির্বাচনের ঊর্ধ্বগামী" প্রয়োজনীয়, তবে এটি প্রাথমিকতম কী, যা দ্রুত তা অনুসন্ধান করার পরে এটি একটি ভয়ানক বোঝা নয়।

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

--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
                );

আমি বুঝতে পারছি এটি পুরানো থ্রেড কিন্তু আমি দেরী করে sqlite3 এ কাজ করছিলাম এবং এই পদ্ধতিতে এসেছি যা গতিশীলভাবে প্যারামিটারাইজড ক্যোয়ারীগুলি তৈরির আমার প্রয়োজনীয়তার সাথে সামঞ্জস্যপূর্ণ:

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;

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

একজন কর্মচারী 300 হলে আমি 300 এর জন্য ডেভিস এর জন্য শেষ নামটি পরিবর্তন করতে চাই। নাহলে, আমি একটি নতুন কর্মচারী যোগ করব।

টেবিল নাম: কর্মচারী কলাম: আইডি, first_name, last_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
;

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

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


এখানে একটি সমাধান যা প্রকৃতপক্ষে একটি ইনসার্ট বা প্রতিস্থাপনের পরিবর্তে একটি ইউপিএসআরটি (আপডেট অথবা ইনসার্ট) হয় (যা অনেক ক্ষেত্রে ভিন্নভাবে কাজ করে)।

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

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

গুরুত্বপূর্ণ বিবরণটি পরিবর্তনগুলি () SQL ফাংশনটি ব্যবহার করতে হয় কিনা তা যাচাই করতে আপডেট বিবৃতি কোন বিদ্যমান রেকর্ড আঘাত করে এবং এটি কোনও রেকর্ড আঘাত না করে শুধুমাত্র সন্নিবেশ বিবৃতিটি সম্পাদন করে।

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

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

টেস্ট আপডেট:

--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;

যদি আপনি বিদ্যমান সারির এক বা একাধিক কলাম সংরক্ষণ করতে চান তবে এরিক বি এর উত্তর ঠিক আছে। আপনি অনেক কলাম সংরক্ষণ করতে চান, এটা খুব কষ্টকর দ্রুত পায়।

এখানে এমন একটি পদ্ধতি যা পাশাপাশি কোনও কলামে ভালভাবে স্কেল করবে। এটি ব্যাখ্যা করার জন্য আমি নিচের স্কিমাটি ধরব:

 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 শুধুমাত্র বিদেশী কীগুলির জন্য ব্যবহার করা হয়, সুতরাং বিন্দুটি স্লাইডাইটের জন্য একটি নতুন সারি সন্নিবেশ করার সময় 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 হবে এবং SQLite তারপরে একটি আইডি স্বয়ংক্রিয়ভাবে বরাদ্দ করবে, কিন্তু যদি ইতিমধ্যে এমন একটি সারি থাকে তবে old.id প্রকৃত মান থাকবে এবং এটি পুনঃব্যবহৃত হবে। যা আমি চেয়েছিলেন ঠিক কি।

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

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


যদি আপনি সাধারণত আপডেট করছেন আমি ..

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

আপনি সাধারণত সন্নিবেশ করা হয় তাহলে আমি চাই

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

এই ভাবে আপনি নির্বাচন এড়াতে এবং আপনি Scllite উপর লেনদেনের শব্দ।


শুধু এই থ্রেড পড়া এবং হতাশ হয়েছে যে এই "UPSERT" inging করা সহজ ছিল না, আমি আরও তদন্ত ...

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

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

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

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


2018-05-18 বন্ধ প্রেস।

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

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

আমি জানি, আমি পার্টি দেরি করেছি কিন্তু ....

UPDATE employee SET role = 'code_monkey', name='fred' WHERE id = 1;
INSERT OR IGNORE INTO employee(id, role, name) values (1, 'code monkey', 'fred');

সুতরাং এটি আপডেট করার চেষ্টা করে, যদি রেকর্ড থাকে তবে সন্নিবেশ কর্ম-সম্পাদন নয়।

অন্যথায়:

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


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

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

INSERT হিসাবে এটি স্বতঃবৃদ্ধি হিসাবে অনুমিত হয় যখন নোট id NULL হতে বাধ্য করা হয়। এটি শুধুমাত্র একটি জেনারেটেড প্রাথমিক কী হলে 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 ব্যবহার new.fieldname


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;




upsert