আপনি FROM ধারাটিতে আপডেটের জন্য লক্ষ্য সারণি নির্দিষ্ট করতে পারবেন না


379

আমার একটি সাধারণ মাইএসকিএল টেবিল রয়েছে:

CREATE TABLE IF NOT EXISTS `pers` (
  `persID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) NOT NULL,
  `gehalt` int(11) NOT NULL,
  `chefID` int(11) DEFAULT NULL,
  PRIMARY KEY (`persID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `pers` (`persID`, `name`, `gehalt`, `chefID`) VALUES
(1, 'blb', 1000, 3),
(2, 'as', 1000, 3),
(3, 'chef', 1040, NULL);

আমি নিম্নলিখিত আপডেট চালানোর চেষ্টা করেছি, তবে আমি কেবল ত্রুটি পেয়েছি 1093:

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE (P.chefID IS NOT NULL 
OR gehalt < 
(SELECT (
    SELECT MAX(gehalt * 1.05) 
    FROM pers MA 
    WHERE MA.chefID = MA.chefID) 
    AS _pers
))

আমি ত্রুটিটি অনুসন্ধান করেছি এবং মাইএসকিএল নিম্নলিখিত পৃষ্ঠাটি থেকে খুঁজে পেয়েছি http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html তবে এটি আমার সাহায্য করে না।

বর্গ কোয়েরিটি সংশোধন করতে আমি কী করব?


উত্তর:


768

সমস্যাটি হ'ল মাইএসকিউএল, কারণ যে কোনও কারণেই নয়, আপনাকে এ জাতীয় প্রশ্ন লিখতে দেয় না:

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM myTable
    INNER JOIN ...
)

এটি হ'ল, যদি আপনি একটি UPDATE/ INSERT/ করছেনDELETE কোনও টেবিলে , আপনি সেই টেবিলটিকে অভ্যন্তরীণ ক্যোয়ারিতে উল্লেখ করতে পারবেন না ( তবে আপনি সেই বাইরের টেবিল থেকে কোনও ক্ষেত্রটি উল্লেখ করতে পারেন ...)


সমাধান উদাহরণস্বরূপ পরিবর্তে হয় myTableসঙ্গে উপ-ক্যোয়ারীতে (SELECT * FROM myTable)এই মত,

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM (SELECT * FROM myTable) AS something
    INNER JOIN ...
)

এটি স্পষ্টতই প্রয়োজনীয় ক্ষেত্রগুলিকে স্পষ্টভাবে একটি অস্থায়ী টেবিলের অনুলিপি করে তোলে, সুতরাং এটি অনুমোদিত।

আমি এই সমাধান খুঁজে পেয়েছি এখানে । এই নিবন্ধ থেকে একটি নোট:

আপনি SELECT * FROM tableবাস্তব জীবনে কেবল উপকণায় যেতে চান না ; আমি কেবল উদাহরণগুলি সহজ রাখতে চেয়েছিলাম। বাস্তবে, আপনাকে কেবল সেই অন্তঃস্থল ক্যোয়ারীতে আপনার প্রয়োজনীয় কলামগুলি নির্বাচন করা উচিত এবং WHEREফলাফলগুলিও সীমাবদ্ধ করার জন্য একটি ভাল ধারা যুক্ত করা উচিত।


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

35
@ সিরাইড: এমএসএসকিউএল বা ওরাকল এর মতো অন্যান্য ডেটাবেসগুলিতে এই স্বেচ্ছাসেবী বাধা নেই
ব্লুরাজা - ড্যানি পিফ্লুঘুফুট

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

33
@ সাইরিড একটি আপেক্ষিক বীজগণিত দৃষ্টিকোণ থেকে Tএবং (SELECT * FROM T)সম্পূর্ণ সমতুল্য। তারা একই সম্পর্ক। অতএব এটি একটি স্বেচ্ছাসেবী, নির্মম বাধা। আরও সুনির্দিষ্টভাবে, এটি মাইএসকিউএলকে এমন কিছু করার জন্য বাধ্যতামূলক করার কাজ যা এটি স্পষ্টভাবে করতে পারে তবে কিছু কারণে এটি তার সহজ আকারে পার্স করতে পারে না।
টোবিয়া

4
আমার ক্ষেত্রে গৃহীত সমাধানটি কার্যকর হয়নি কারণ আমার টেবিলটি খুব বড়। কোয়েরিটি কখনই শেষ হয়নি। স্পষ্টতই এটি অনেকগুলি অভ্যন্তরীণ সংস্থান নিচ্ছে। পরিবর্তে আমি অভ্যন্তরীণ প্রশ্নের সাথে একটি ভিউ তৈরি করেছি এবং এটি ডেটা নির্বাচনের জন্য ব্যবহার করেছি, যা একেবারে দুর্দান্ত কাজ করেছে। DELETE FROM t WHERE tableID NOT IN (SELECT viewID FROM t_view);এছাড়াও আমি OPTIMIZE TABLE t;টেবিলের আকার কমাতে পরে চালানোর পরামর্শ দিচ্ছি ।
কোডেক্স

53

আপনি এটি তিনটি ধাপে তৈরি করতে পারেন:

CREATE TABLE test2 AS
SELECT PersId 
FROM pers p
WHERE (
  chefID IS NOT NULL 
  OR gehalt < (
    SELECT MAX (
      gehalt * 1.05
    )
    FROM pers MA
    WHERE MA.chefID = p.chefID
  )
)

...

UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE PersId
IN (
  SELECT PersId
  FROM test2
)
DROP TABLE test2;

অথবা

UPDATE Pers P, (
  SELECT PersId
  FROM pers p
  WHERE (
   chefID IS NOT NULL 
   OR gehalt < (
     SELECT MAX (
       gehalt * 1.05
     )
     FROM pers MA
     WHERE MA.chefID = p.chefID
   )
 )
) t
SET P.gehalt = P.gehalt * 1.05
WHERE p.PersId = t.PersId

16
হ্যাঁ, বেশিরভাগ subqueries CREATE TABLEবিবৃতি সহ একাধিক পদক্ষেপ হিসাবে পুনরায় লেখা যেতে পারে - আমি আশা করি লেখক এটি সম্পর্কে অবগত ছিলেন। তবে, এটাই কি একমাত্র সমাধান? অথবা কোয়েরিটি subqueries বা যোগদানের সাথে পুনরায় লেখা যেতে পারে? এবং কেন (না) তা করে?
কোনারাক

আমি মনে করি আপনার দ্বিতীয় সমাধানটিতে আপনার মূলধন ত্রুটি রয়েছে। UPDATE Pers Pপড়া উচিত নয় UPDATE pers P?
সর্বব্যাপীব্যাকন

2
এই সমাধানটি চেষ্টা করে এবং অস্থায়ী / দ্বিতীয় সারণীতে প্রচুর সংখ্যক প্রবেশের জন্য ক্যোয়ারীটি খুব ধীর হতে পারে; একটি সূচক / প্রাথমিক কী সহ অস্থায়ী / দ্বিতীয় সারণী তৈরি করার চেষ্টা করুন [দেখুন dev.mysql.com/doc/refman/5.1/en/create-table-select.html ]
অ্যালেক্স

@ কেনারাক যেমন বলেছে, এটি সত্যিই সেরা উত্তর নয়। নীচের নীলরাজের উত্তর আমার কাছে সেরা বলে মনে হচ্ছে। উপভোটরা একমত বলে মনে হচ্ছে।
ShatyUT

@ কেনারাক, CREATE TABLE AS SELECTভয়ঙ্কর পারফরম্যান্স দেয় না ?
পেসারিয়ার

27

মাইএসকিএলে, আপনি একই টেবিলটিকে সাবকিউরি করে একটি টেবিল আপডেট করতে পারবেন না।

আপনি কোয়েরিটি দুটি অংশে আলাদা করতে পারেন বা করতে পারেন

 টেবিল_এএস আপডেট করুন
 আন্ডার জিল ট্যাবলেট_এ বি বি এ.ফিল্ড 1 = বিফিল্ড 1
 সেট ফিল্ড 2 =? 

5
SELECT ... SET? আমি এই সম্পর্কে কখনও শুনিনি।
সার্জ এস।

@ গ্রিসন স্পষ্টির জন্য ধন্যবাদ। এখন আমি পেয়েছি কেন আমার আইএন ক্লজটি কাজ করে না - আমি একই টেবিলটিকে লক্ষ্য করেছিলাম।
অ্যান্টনি

2
... এটি আসলে কাজ করে না বলে মনে হচ্ছে। এটি এখনও আমাকে একই ত্রুটি দিচ্ছে।
ব্লুরাজা - ড্যানি পিফ্লুঘুফুট

2
এই উত্তরটি আরও সঠিক এবং দক্ষ জিনিসটি AS Bকরে যা দ্বিতীয় রেফারেন্সটিতে ব্যবহার করছে TABLE_A। সর্বাধিক-উত্সাহিত উদাহরণের উত্তরটি AS Tসম্ভাব্য অদক্ষের পরিবর্তে ব্যবহার করে সরল করা যেতে পারে FROM (SELECT * FROM myTable) AS something, যা ভাগ্যক্রমে ক্যোরি অপ্টিমাইজার সাধারণত মুছে ফেলে তবে সর্বদা তা না করে।
নাটব্রো

23

একটি subquery থেকে একটি অস্থায়ী টেবিল (টেম্প্প) তৈরি করুন

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE P.persID IN (
    SELECT tempP.tempId
    FROM (
        SELECT persID as tempId
        FROM pers P
        WHERE
            P.chefID IS NOT NULL OR gehalt < 
                (SELECT (
                    SELECT MAX(gehalt * 1.05) 
                    FROM pers MA 
                    WHERE MA.chefID = MA.chefID) 
                    AS _pers
                )
    ) AS tempP
)

আমি একটি পৃথক নাম (ওরফে) প্রবর্তন করেছি এবং অস্থায়ী টেবিলের জন্য 'persID' কলামে একটি নতুন নাম দিয়েছি


অভ্যন্তরীণ অভ্যন্তরীণ নির্বাচনের পরিবর্তে মানগুলি ভেরিয়েবলগুলিতে কেন নির্বাচন করবেন না?
পেসারিয়ার

SELECT ( SELECT MAX(gehalt * 1.05)..- প্রথমটি SELECTকোনও কলাম নির্বাচন করে না।
ইসতিয়াক আহমেদ

18

এটা বেশ সহজ। উদাহরণস্বরূপ, লেখার পরিবর্তে:

INSERT INTO x (id, parent_id, code) VALUES (
    NULL,
    (SELECT id FROM x WHERE code='AAA'),
    'BBB'
);

আপনার লেখা উচিত

INSERT INTO x (id, parent_id, code)
VALUES (
    NULL,
    (SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'),
    'BBB'
);

অথবা সাদৃশ্যপূর্ণ.


13

নীলরাজ দ্বারা পোস্ট করা পদ্ধতিটি ধীর গতিতে আমি টেবিল থেকে নকল মুছতে ব্যবহার করার সাথে সাথে এটি পরিবর্তন করেছি। যদি এটি বড় টেবিল সহ যে কাউকে সহায়তা করে তবে মূল জিজ্ঞাসা

delete from table where id not in (select min(id) from table group by field 2)

এটি আরও সময় নিচ্ছে:

DELETE FROM table where ID NOT IN(
  SELECT MIN(t.Id) from (select Id,field2 from table) AS t GROUP BY field2)

দ্রুত সমাধান

DELETE FROM table where ID NOT IN(
   SELECT x.Id from (SELECT MIN(Id) as Id from table GROUP BY field2) AS t)

আপনি যদি নিম্নমানের হন তবে একটি মন্তব্য যুক্ত করুন।
আজাক 6


3

আপনি যদি টেবিলএ থেকে ফিল্ডএ পড়ার চেষ্টা করছেন এবং একই টেবিলের ফিল্ড বি এ সংরক্ষণ করতে পারেন, যখন ফিল্ডসি = ফিল্ড করা আপনি এটি বিবেচনা করতে পারেন।

UPDATE tableA,
    tableA AS tableA_1 
SET 
    tableA.fieldB= tableA_1.filedA
WHERE
    (((tableA.conditionFild) = 'condition')
        AND ((tableA.fieldc) = tableA_1.fieldd));

কন্ডিশন-ফিল্ড আপনার শর্ত পূরণ করার সময় উপরে কোডটি ফিল্ডএ থেকে ফিল্ড বিতে অনুলিপি করে। এটি এডিওতেও কাজ করে (যেমন অ্যাক্সেস)

উত্স: আমার চেষ্টা


3

মারিয়াডিবি এটি 10.3.x থেকে শুরু করেছে (উভয়র জন্য DELETEএবং UPDATE):

আপডেট - একই উত্স এবং লক্ষ্য সহ বিবৃতি

মারিয়াডিবি 10.3.2 থেকে, আপডেটের বিবৃতিতে একই উত্স এবং লক্ষ্য থাকতে পারে।

মারিয়াডিবি 10.3.1 অবধি নিম্নলিখিত আপডেটের বিবৃতিটি কাজ করবে না:

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
  ERROR 1093 (HY000): Table 't1' is specified twice, 
  both as a target for 'UPDATE' and as a separate source for data

মারিয়াডিবি 10.3.2 থেকে, বিবৃতিটি সফলভাবে সম্পাদন করেছে:

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);

মোছা - একই উত্স এবং লক্ষ্য সারণী

মারিয়াডিবি 10.3.1 অবধি, একই উত্স এবং লক্ষ্য সহ কোনও টেবিল থেকে মোছা সম্ভব ছিল না। মারিয়াডিবি 10.3.1 থেকে, এটি এখন সম্ভব। উদাহরণ স্বরূপ:

DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);

ডিবিফিডাল মারিয়াডিবি 10.2 - ত্রুটি

ডিবিফিডাল মারিয়াডিবি 10.3 - সাফল্য


0

অন্যান্য কাজের ক্ষেত্রগুলির মধ্যে সাবকিউরিতে SELECT DISTINCT বা LIMIT ব্যবহার করা অন্তর্ভুক্ত রয়েছে, যদিও এগুলি বস্তুগতকরণের ক্ষেত্রে তাদের প্রভাবের মতো স্পষ্ট নয়। এটি আমার জন্য কাজ করেছে

যেমনটি মাইএসকিএল ডকে উল্লিখিত হয়েছে

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