উপস্থিত না থাকলে এসকিউএল সার্ভার .োকান


243

আমি আমার টেবিলের মধ্যে ডেটা toোকাতে চাই, তবে কেবলমাত্র ডেটা sertোকান যা ইতিমধ্যে আমার ডাটাবেসে বিদ্যমান নেই।

আমার কোডটি এখানে:

ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
  (@_DE nvarchar(50),
   @_ASSUNTO nvarchar(50),
   @_DATA nvarchar(30) )
AS
BEGIN
   INSERT INTO EmailsRecebidos (De, Assunto, Data)
   VALUES (@_DE, @_ASSUNTO, @_DATA)
   WHERE NOT EXISTS ( SELECT * FROM EmailsRecebidos 
                   WHERE De = @_DE
                   AND Assunto = @_ASSUNTO
                   AND Data = @_DATA);
END

এবং ত্রুটিটি হ'ল:

এমএসজি 156, স্তর 15, রাজ্য 1, প্রক্রিয়া ইমেলসিসিবিডোস প্রবেশ করুন, লাইন 11
'WHERE' শব্দটির কাছে ভুল সিনট্যাক্স।


10
কোনও অনুলিপি নিশ্চিত করতে আপনার একা এই চেকের উপর নির্ভর করা উচিত নয়, এটি থ্রেডটি নিরাপদ নয় এবং কোনও রেসের শর্ত পূরণ হওয়ার পরে আপনি সদৃশগুলি পাবেন। আপনার যদি সত্যিই অনন্য ডেটার প্রয়োজন হয় তবে টেবিলটিতে একটি অনন্য বাধা যুক্ত করুন এবং তারপরে অনন্য সীমাবদ্ধতা লঙ্ঘনের ত্রুটিটি ধরুন। এই উত্তরটি দেখুন
গ্যারেথডি

1
আপনি মার্জ কোয়েরি ব্যবহার করতে পারেন বা উপস্থিত না থাকলে (বিবৃতি নির্বাচন করুন) মান সন্নিবেশ শুরু করুন
আবদুল হান্নান ইজাজ

আপনার যদি এই চেকটিতে রিলে করা উচিত বা না করা উচিত তবে এটি দৃশ্যের উপর নির্ভর করে। আপনি উদাহরণস্বরূপ একটি "স্থিতিশীল" টেবিলটিতে ডেটা লেখার জন্য কোনও স্ক্রিপ্ট মোতায়েনের বিকাশ করছেন যদি, এটি কোনও সমস্যা নয়।
এক্সেলওয়াস

আপনি "যদি বিদ্যমান না থাকে (এই থেকে ... * নির্বাচন করুন" ব্যবহার করতে পারেন এই স্ট্যাকওভারফ্লো
.

2
@ গ্যারেথডি: "থ্রেড নিরাপদ নয়" এর অর্থ কী? এটি মার্জিত নাও হতে পারে তবে এটি আমার কাছে সঠিক দেখাচ্ছে। একটি একক insertবিবৃতি সর্বদা একটি লেনদেন হয়। এটি এমন নয় যে এসকিউএল সার্ভার সাবউয়েরিটি প্রথমে মূল্যায়ন করে এবং পরে কোনও কোনও সময়ে, এবং কোনও লক না রেখে সন্নিবেশটি চালিয়ে যায়।
এড অ্যাভিস

উত্তর:


322

পরিবর্তে কোড নীচে

BEGIN
   INSERT INTO EmailsRecebidos (De, Assunto, Data)
   VALUES (@_DE, @_ASSUNTO, @_DATA)
   WHERE NOT EXISTS ( SELECT * FROM EmailsRecebidos 
                   WHERE De = @_DE
                   AND Assunto = @_ASSUNTO
                   AND Data = @_DATA);
END

প্রতিস্থাপন

BEGIN
   IF NOT EXISTS (SELECT * FROM EmailsRecebidos 
                   WHERE De = @_DE
                   AND Assunto = @_ASSUNTO
                   AND Data = @_DATA)
   BEGIN
       INSERT INTO EmailsRecebidos (De, Assunto, Data)
       VALUES (@_DE, @_ASSUNTO, @_DATA)
   END
END

আপডেট হয়েছে: (নির্দেশ করার জন্য @ মার্ক ডুরডিনকে ধন্যবাদ)

নোট করুন যে উচ্চ লোডের নীচে, এটি এখনও কখনও কখনও ব্যর্থ হয়, কারণ দ্বিতীয় সংযোগটি যদি প্রথম সংযোগ INSERT কার্যকর করার আগে পরীক্ষা না করে পরীক্ষা পাস করতে পারে, অর্থাত একটি জাতি শর্ত। লেনদেনের মোড়ক এমনকি কেন মোড়ানো এই সমস্যার সমাধান করে না তার একটি উত্তরের উত্তরের জন্য stackoverflow.com/a/3791506/1836776 দেখুন ।


20
নোট করুন যে উচ্চ লোডের নিচে, এটি এখনও কখনও কখনও ব্যর্থ হয়, কারণ দ্বিতীয় সংযোগটি যদি প্রথম সংযোগটি INSERT কার্যকর করার আগে পরীক্ষা না করে পরীক্ষা পাস করতে পারে, অর্থাত একটি জাতি শর্ত। কেন কোনও লেনদেনের মোড়ক এমনকি কেন এই সমস্যার সমাধান করে না তার একটি উত্তরের উত্তরের জন্য দেখুন স্ট্যাকওভারফ্লো.com/ a/ 3791506/1836776
মার্ক দুরদিন 6

11
ইমেলগুলি থেকে প্রথম নির্বাচন করুন নিখুঁত যেখানে @ =__DE এবং Assunto = @_ASSUNTO এবং ডেটা = @_ ডেটা * এর পরিবর্তে 1 ব্যবহার করা আরও কার্যকর হবে
রেনো

1
পুরো জিনিসটির চারপাশে একটি রাইটিং লক রাখুন এবং তারপরে আপনার নকলের কোনও সুযোগ থাকবে না।
কেভিন ফিংকেনবাইন্ডার

10
select *এই ক্ষেত্রে @ জাজকাট কোনও ক্ষেত্রেই কোনও পার্থক্য রাখে না কারণ এটি একটি ধারাতে ব্যবহৃত হচ্ছে EXISTS। এসকিউএল সার্ভার সর্বদা এটি অপ্টিমাইজ করবে এবং যুগ যুগ ধরে এটি করে আসছে। যেহেতু আমার বয়স অনেক বেশি আমি সাধারণত এই কোয়েরিগুলি লিখি EXISTS (SELECT 1 FROM...)তবে এটির আর প্রয়োজন হয় না।
লাউডেনভিয়ার

16
এই ধরণের সাধারণ প্রশ্নটি কেন নিশ্চিততার চেয়ে সন্দেহের জন্ম দেয়?
ড্রোভা

77

দ্রুততম পথ সন্ধানকারীদের জন্য , আমি সম্প্রতি এই বেঞ্চমার্কগুলি জুড়ে এসেছি যেখানে স্পষ্টতই "INSERT SELECT ... ছাড় নির্বাচন ..." ব্যবহার করে 50 মিলিয়ন রেকর্ড বা তারও বেশি দ্রুততম হিসাবে প্রমাণিত হয়েছিল।

নিবন্ধটি থেকে এখানে কিছু নমুনা কোড দেওয়া হয়েছে (কোডের তৃতীয় ব্লকটি দ্রুততম ছিল):

INSERT INTO #table1 (Id, guidd, TimeAdded, ExtraData)
SELECT Id, guidd, TimeAdded, ExtraData
FROM #table2
WHERE NOT EXISTS (Select Id, guidd From #table1 WHERE #table1.id = #table2.id)
-----------------------------------
MERGE #table1 as [Target]
USING  (select Id, guidd, TimeAdded, ExtraData from #table2) as [Source]
(id, guidd, TimeAdded, ExtraData)
    on [Target].id =[Source].id
WHEN NOT MATCHED THEN
    INSERT (id, guidd, TimeAdded, ExtraData)
    VALUES ([Source].id, [Source].guidd, [Source].TimeAdded, [Source].ExtraData);
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT id, guidd, TimeAdded, ExtraData from #table2
EXCEPT
SELECT id, guidd, TimeAdded, ExtraData from #table1
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT #table2.id, #table2.guidd, #table2.TimeAdded, #table2.ExtraData
FROM #table2
LEFT JOIN #table1 on #table1.id = #table2.id
WHERE #table1.id is null

6
আমি ছাড়ার পছন্দ পছন্দ করি
ব্রায়ান

1
প্রথমবার আমি এক্সেসটি ব্যবহার করেছি। সহজ এবং মার্জিত।
jhowe

তবে এক্সক্লুসিটি বাল্ক পরিচালনার জন্য দক্ষ নাও হতে পারে।
আশিষ কে। শর্মা

এক্সেসপটি তেমন দক্ষ নয়।
বিশ্ব

1
@ বিসওয়া: এই মানদণ্ড অনুসারে নয়। কোডটি সাইট থেকে পাওয়া যায়। ফলাফলগুলি কীভাবে তুলনা করে তা দেখতে আপনার সিস্টেমে নির্দ্বিধায় এটি ব্যবহার করুন।

25

আমি একত্রীকরণটি ব্যবহার করব:

create PROCEDURE [dbo].[EmailsRecebidosInsert]
  (@_DE nvarchar(50),
   @_ASSUNTO nvarchar(50),
   @_DATA nvarchar(30) )
AS
BEGIN
   with data as (select @_DE as de, @_ASSUNTO as assunto, @_DATA as data)
   merge EmailsRecebidos t
   using data s
      on s.de = t.de
     and s.assunte = t.assunto
     and s.data = t.data
    when not matched by target
    then insert (de, assunto, data) values (s.de, s.assunto, s.data);
END

আমি এর সাথে যাচ্ছি কারণ এর অনুরাগী
জোকব

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

20

কোড নীচে চেষ্টা করুন

ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
  (@_DE nvarchar(50),
   @_ASSUNTO nvarchar(50),
   @_DATA nvarchar(30) )
AS
BEGIN
   INSERT INTO EmailsRecebidos (De, Assunto, Data)
   select @_DE, @_ASSUNTO, @_DATA
   EXCEPT
   SELECT De, Assunto, Data from EmailsRecebidos
END

11

INSERTকমান্ড একটি নেই WHEREদফা - আপনি এটি এমন একটি লেখার জন্য থাকবে না:

ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
  (@_DE nvarchar(50),
   @_ASSUNTO nvarchar(50),
   @_DATA nvarchar(30) )
AS
BEGIN
   IF NOT EXISTS (SELECT * FROM EmailsRecebidos 
                   WHERE De = @_DE
                   AND Assunto = @_ASSUNTO
                   AND Data = @_DATA)
   BEGIN
       INSERT INTO EmailsRecebidos (De, Assunto, Data)
       VALUES (@_DE, @_ASSUNTO, @_DATA)
   END
END

1
এই পদ্ধতির জন্য আপনাকে ত্রুটিগুলি পরিচালনা করতে হবে কারণ চেক এবং সন্নিবেশকরণের মধ্যে এমন কিছু ঘটনা ঘটবে যেখানে কোনও সন্নিবেশ ঘটবে।
ফিলিপ ডি ভোস

@ ফিলিপডেভোস: সত্য - একটি সম্ভাবনা, সম্ভবত খুব সম্ভবত নয়, তবে এখনও একটি সম্ভাবনা। ভাল যুক্তি.
marc_s

আপনি যদি লেনদেনের মধ্যে উভয়কে মুড়ে রাখেন তবে কী হবে? এটা কি সম্ভাবনাটিকে বাধা দেবে? (আমি লেনদেনের কোনও বিশেষজ্ঞ নই, তাই দয়া করে যদি এটি একটি মূ question় প্রশ্ন হয় তবে ক্ষমা করুন))
ডেভিড

1
দেখুন stackoverflow.com/a/3791506/1836776 কেন একটি লেনদেন এই সমস্যার সমাধানের নয়, @David একটি ভাল উত্তরের জন্য।
মার্ক দুরদিন 6

যদি আইএফ বিবৃতিতে: প্রয়োজনীয় কমান্ড লাইনগুলির সংখ্যা যদি একাধিক লাইন ব্যবহার করেও কেবল একটি হয় তবে BEGIN & END ব্যবহার করার দরকার নেই, সুতরাং আপনি এটি এখানে বাদ দিতে পারেন।
ওয়াসাম এল মাহডি

11

আমি এসকিউএল সার্ভার ২০১২ এর সাথে একই কাজ করেছি এবং এটি কার্যকর হয়েছে

Insert into #table1 With (ROWLOCK) (Id, studentId, name)
SELECT '18769', '2', 'Alex'
WHERE not exists (select * from #table1 where Id = '18769' and studentId = '2')

4
অবশ্যই এটি কাজ করেছিল, আপনি একটি অস্থায়ী টেবিল ব্যবহার করছেন (যেমন অস্থায়ী টেবিলগুলি ব্যবহার করার সময় আপনার সম্মতি সম্পর্কে চিন্তা করার দরকার নেই)।
দ্রোয়া

6

যদি থেকে সরাইয়া SQL সার্ভার সংস্করণটি (? 2012) উপর নির্ভর করে বিদ্যমান তাই আপনি এছাড়াও ব্যবহার করতে পারেন একত্রীকরণ যেমন:

ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
    ( @_DE nvarchar(50)
    , @_ASSUNTO nvarchar(50)
    , @_DATA nvarchar(30))
AS BEGIN
    MERGE [dbo].[EmailsRecebidos] [Target]
    USING (VALUES (@_DE, @_ASSUNTO, @_DATA)) [Source]([De], [Assunto], [Data])
         ON [Target].[De] = [Source].[De] AND [Target].[Assunto] = [Source].[Assunto] AND [Target].[Data] = [Source].[Data]
     WHEN NOT MATCHED THEN
        INSERT ([De], [Assunto], [Data])
        VALUES ([Source].[De], [Source].[Assunto], [Source].[Data]);
END

2

বিভিন্ন এসকিউএল, একই নীতি। যেখানে সারণি নেই সেখানে ব্যর্থ হলে কেবল sertোকান

INSERT INTO FX_USDJPY
            (PriceDate, 
            PriceOpen, 
            PriceLow, 
            PriceHigh, 
            PriceClose, 
            TradingVolume, 
            TimeFrame)
    SELECT '2014-12-26 22:00',
           120.369000000000,
           118.864000000000,
           120.742000000000,
           120.494000000000,
           86513,
           'W'
    WHERE NOT EXISTS
        (SELECT 1
         FROM FX_USDJPY
         WHERE PriceDate = '2014-12-26 22:00'
           AND TimeFrame = 'W')

-1

যেমন নীচের কোডে ব্যাখ্যা করা হয়েছে: নীচে কোয়েরিগুলি সম্পাদন করুন এবং নিজেকে যাচাই করুন।

CREATE TABLE `table_name` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `tele` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB;

একটি রেকর্ড sertোকান:

INSERT INTO table_name (name, address, tele)
SELECT * FROM (SELECT 'Nazir', 'Kolkata', '033') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_name WHERE name = 'Nazir'
) LIMIT 1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

SELECT * FROM `table_name`;

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Nazir  | Kolkata   | 033  |
+----+--------+-----------+------+

এখন আবার একই রেকর্ডটি toোকানোর চেষ্টা করুন:

INSERT INTO table_name (name, address, tele)
SELECT * FROM (SELECT 'Nazir', 'Kolkata', '033') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_name WHERE name = 'Nazir'
) LIMIT 1;

Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Nazir  | Kolkata   | 033  |
+----+--------+-----------+------+

একটি ভিন্ন রেকর্ড Inোকান:

INSERT INTO table_name (name, address, tele)
SELECT * FROM (SELECT 'Santosh', 'Kestopur', '044') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_name WHERE name = 'Santosh'
) LIMIT 1;

Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

SELECT * FROM `table_name`;

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Nazir  | Kolkata   | 033  |
|  2 | Santosh| Kestopur  | 044  |
+----+--------+-----------+------+

1
এটি কি মাইএসকিউএলের জন্য নয় এবং প্রশ্নটি এসকিউএল সার্ভারের জন্য নয়?
ডগলাস গ্যাসকেল

হ্যাঁ এটি মাইএসকিউএল এর জন্য।
বদিরাজ জাহাগীরদার

-2

আপনি GOকমান্ডটি ব্যবহার করতে পারেন । এটি ত্রুটির পরে এসকিউএল স্টেটমেন্টগুলির সম্পাদন পুনরায় চালু করবে। আমার ক্ষেত্রে আমার কয়েকটি 1000 ইনসার্ট স্টেটমেন্ট রয়েছে, যেখানে সেই মুষ্টিমেয় রেকর্ডগুলির একটি ইতিমধ্যে ডাটাবেসে উপস্থিত রয়েছে, আমি ঠিক জানি না কোনটি। আমি দেখেছি যে কয়েকটি 100 প্রক্রিয়াকরণের পরে, মৃত্যুদন্ড কার্যকর হওয়া একটি ত্রুটি বার্তা দিয়ে থামিয়ে দেয় INSERTযা রেকর্ডটি ইতিমধ্যে বিদ্যমান হিসাবে এটি করতে পারে না । বেশ বিরক্তিকর, তবে এটি GOসমাধান করা। এটি দ্রুততম সমাধান নাও হতে পারে তবে গতি আমার সমস্যা ছিল না।

GO
INSERT INTO mytable (C1,C2,C3) VALUES(1,2,3)
GO
INSERT INTO mytable (C1,C2,C3) VALUES(4,5,6)
 etc ...

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