উপস্থিতি (নির্বাচন 1…) বনাম উপস্থিতি (নির্বাচন করুন…)) এক না অন্য?


37

যখনই আমার কোনও টেবিলে কিছু সারিটির অস্তিত্বের জন্য যাচাই করা দরকার, আমি সর্বদা একটি শর্ত লেখার প্রবণতা রাখি:

SELECT a, b, c
  FROM a_table
 WHERE EXISTS
       (SELECT *  -- This is what I normally write
          FROM another_table
         WHERE another_table.b = a_table.b
       )

অন্য কিছু লোক এটি লিখেন:

SELECT a, b, c
  FROM a_table
 WHERE EXISTS
       (SELECT 1   --- This nice '1' is what I have seen other people use
          FROM another_table
         WHERE another_table.b = a_table.b
       )

যখন শর্তটি NOT EXISTSপরিবর্তে হয় EXISTS: কিছু ক্ষেত্রে, আমি এটি একটি LEFT JOINএবং একটি অতিরিক্ত শর্ত দিয়ে লিখতে পারি (কখনও কখনও অ্যান্টিজাইন বলা হয় ):

SELECT a, b, c
  FROM a_table
       LEFT JOIN another_table ON another_table.b = a_table.b
 WHERE another_table.primary_key IS NULL

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

  1. এর পরিবর্তে কি কোনও পার্থক্য (শৈলী ব্যতীত) ব্যবহার করতে SELECT 1হবে SELECT *?
    এমন কোনও কর্নার কেস আছে যেখানে এটি একই রকম আচরণ করে না?

  2. যদিও আমি যা লিখেছি তা হ'ল (এএফআইএকি) স্ট্যান্ডার্ড এসকিউএল: বিভিন্ন ডাটাবেস / পুরানো সংস্করণগুলির জন্য কি এইরকম পার্থক্য রয়েছে?

  3. অ্যান্টিজোইন লেখার স্পষ্টত্বে কোনও লাভ আছে কি?
    সমসাময়িক পরিকল্পনাকারী / অপ্টিমাইজাররা কি এই NOT EXISTSধারাটি থেকে আলাদা আচরণ করে ?


5
নোট করুন যে PostgreSQL কলাম ছাড়াই নির্বাচনকে সমর্থন করে, যাতে আপনি কেবল লিখতে পারেন EXISTS (SELECT FROM ...)
ডানফোল্ড

1
আমি কয়েক বছর আগে এসও তে প্রায় একই প্রশ্নটি জিজ্ঞাসা করছি: স্ট্যাকওভারফ্লো.com
এরউইন ব্র্যান্ডসেটেটার

উত্তর:


45

না, সমস্ত বড় ডিবিএমএসের মধ্যে (NOT) EXISTS (SELECT 1 ...)এবং দক্ষতার মধ্যে কোনও পার্থক্য নেই (NOT) EXISTS (SELECT * ...)। আমি প্রায়শই (NOT) EXISTS (SELECT NULL ...)ব্যবহার করাও দেখেছি ।

কিছুতে আপনি লিখতেও পারেন (NOT) EXISTS (SELECT 1/0 ...)এবং ফলাফলটিও একই - কোনও (শূন্য দ্বারা বিভাজন) ত্রুটি ছাড়াই, যা প্রমাণ করে যে সেখানে প্রকাশটি এমনকি মূল্যায়ন করা হয় না।


LEFT JOIN / IS NULLঅ্যান্টিজোন পদ্ধতি সম্পর্কে , একটি সংশোধন: এটি সমান NOT EXISTS (SELECT ...)

এই ক্ষেত্রে, NOT EXISTSবনামLEFT JOIN / IS NULL, আপনি বিভিন্ন কার্যকর করার পরিকল্পনা পেতে পারেন। উদাহরণস্বরূপ মাইএসকিউএল এবং বেশিরভাগ পুরানো সংস্করণগুলিতে (5..7 এর আগে) পরিকল্পনাগুলি মোটামুটি একই রকম তবে অভিন্ন হবে না। অন্যান্য ডিবিএমএসের অপ্টিমাইজার (এসকিউএল সার্ভার, ওরাকল, পোস্টগ্রিস, ডিবি 2) - যতদূর আমি জানি - এই 2 টি পদ্ধতি পুনরায় লেখার জন্য এবং উভয়ের জন্য একই পরিকল্পনা বিবেচনা করতে কম-বেশি সক্ষম। তবুও, এরকম কোনও গ্যারান্টি নেই এবং অপ্টিমাইজেশান করার সময়, বিভিন্ন সমতুল্য পুনর্লিখনের পরিকল্পনাগুলি পরীক্ষা করা ভাল কারণ প্রতিটি অপ্টিমাইজার পুনরায় লিখন না করার ক্ষেত্রে যেমন হতে পারে (যেমন জটিল প্রশ্নগুলি, অনেকগুলি যোগদান এবং / অথবা উত্পন্ন টেবিল / সাবকিউয়ের অভ্যন্তরে সাবকিউরিস, যেখানে একাধিক টেবিলের শর্তাবলী, যোগদানের শর্তে ব্যবহৃত সংমিশ্রণ কলামগুলি) বা অপ্টিমাইজারের পছন্দ এবং পরিকল্পনাগুলি উপলভ্য সূচীগুলি, সেটিংস ইত্যাদি দ্বারা পৃথকভাবে প্রভাবিত হয় are

এছাড়াও লক্ষ করুন যে USINGসমস্ত ডিবিএমএসে (উদাহরণস্বরূপ এসকিউএল সার্ভার) ব্যবহার করা যাবে না। আরও সাধারণ JOIN ... ONকাজ সর্বত্র।
এবং আমাদের সাথে SELECTযোগদানের পরে ত্রুটি / অস্পষ্টতা এড়াতে কলামগুলিকে টেবিলের নাম / উপনামের সাথে উপসর্গ করা প্রয়োজন।
আমি সাধারণত যোগদানের কলামটিকে IS NULLচেকের মধ্যে রাখতে পছন্দ করি (যদিও পিকে বা কোনও অ-শর্তযুক্ত কলাম ঠিক আছে, এটি দক্ষতার জন্য কার্যকর হতে পারে যখন কোনও LEFT JOINক্লাস্টারযুক্ত সূচক ব্যবহার করার পরিকল্পনা করা হয় ):

SELECT a_table.a, a_table.b, a_table.c
  FROM a_table
       LEFT JOIN another_table 
           ON another_table.b = a_table.b
 WHERE another_table.b IS NULL ;

অ্যান্টিজোইনগুলির ব্যবহারের জন্য একটি তৃতীয় পদ্ধতিও NOT INরয়েছে তবে যদি অভ্যন্তরীণ সারণীর কলামটি নালাগ্র হয় তবে এর আলাদা শব্দার্থক (এবং ফলাফল!) রয়েছে has এটি সারিগুলি বাদ দিয়ে NULL, ক্যোরিটিকে আগের 2 সংস্করণের সমতুল্য করেই ব্যবহার করা যেতে পারে :

SELECT a, b, c
  FROM a_table
 WHERE a_table.b NOT IN 
       (SELECT another_table.b
          FROM another_table
         WHERE another_table.b IS NOT NULL
       ) ;

এটি বেশিরভাগ ডিবিএমএসেও একই রকম পরিকল্পনা দেয়।


1
মাইএসকিউএল খুব সাম্প্রতিক সংস্করণটি পর্যন্ত, [NOT] IN (SELECT ...)যদিও সমতুল্য, সঞ্চালিত খুব দুর্বল। এটা এড়ানোর!
রিক জেমস

3
পোস্টগ্র্রেএসকিউএল-র ক্ষেত্রে এটি সত্য নয়SELECT *অবশ্যই আরও কাজ করছে। আমি সরলতার জন্য ব্যবহারের পরামর্শ দেবSELECT 1
ইভান ক্যারল

11

এমন এক বিভাগের ক্ষেত্রে রয়েছে যেখানে SELECT 1এবং SELECT *বিনিময়যোগ্য নয় - বিশেষত, এই ক্ষেত্রে একটি সর্বদা গ্রহণযোগ্য হবে এবং অন্যটি বেশিরভাগ ক্ষেত্রে তা হবে না।

আমি মামলা যেখানে আপনি একটি সারি অস্তিত্বের চেক করতে হবে কথা বলছি দলবদ্ধ সেট। যদি টেবিলটিতে Tকলাম থাকে C1এবং C2আপনি সারি গোষ্ঠীগুলির একটি নির্দিষ্ট শর্তের সাথে মেলে এমন অস্তিত্বের সন্ধান করছেন, আপনি এটি ব্যবহার করতে পারেন SELECT 1:

EXISTS
(
  SELECT
    1
  FROM
    T
  GROUP BY
    C1
  HAVING
    AGG(C2) = SomeValue
)

তবে আপনি SELECT *একইভাবে ব্যবহার করতে পারবেন না ।

এটি নিছক একটি সিনট্যাকটিক দিক। যেখানে উভয় বিকল্পগুলি সিনট্যাকটিকভাবে গৃহীত হয়েছে, সম্ভবত অন্যান্য কার্য সম্পাদনের ক্ষেত্রে বা ফলাফলের দিক থেকে আপনার কোনও পার্থক্য থাকবে না, যেমন অন্য উত্তরে বর্ণিত হয়েছে ।

মন্তব্য অনুসরণ করে অতিরিক্ত নোট

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

পোস্টগ্রিএসকিউএল হ'ল একটি আরডিবিএমএস যেখানে SELECT *ব্যর্থ হতে পারে, তবে এখনও কিছু ক্ষেত্রে কাজ করতে পারে। বিশেষত, আপনি যদি পিকে দ্বারা দলবদ্ধ করে থাকেন তবে SELECT *ভাল কাজ করবে, অন্যথায় বার্তাটি দিয়ে এটি ব্যর্থ হবে:

ত্রুটি: "T.C2" কলামটি অবশ্যই গ্রুপের মাধ্যমে গ্রুপে উপস্থিত হতে হবে বা একটি সামগ্রিক ফাংশনে ব্যবহৃত হবে


1
ভাল পয়েন্ট, যদিও এটি আমি উদ্বিগ্ন ছিল ঠিক তেমনটি নয়। এটি একটি ধারণাগত পার্থক্য দেখায় । কারণ, যখন আপনি GROUP BY, ধারণাটি *অর্থহীন (বা কমপক্ষে, এটি পরিষ্কার নয়)।
joanolo

5

ক্লজটি পুনরায় লেখার একটি যুক্তিযুক্ত আকর্ষণীয় উপায় EXISTSযা ক্লিনারের ফলস্বরূপ, এবং কম কম বিভ্রান্তিকর ক্যোয়ারী অন্তত এসকিউএল সার্ভারে হতে পারে:

SELECT a, b, c
  FROM a_table
 WHERE b = ANY
       (
          SELECT b
          FROM another_table
       );

এর অ্যান্টি-সেমি-জয়েন সংস্করণটি দেখতে পাবেন:

SELECT a, b, c
  FROM a_table
 WHERE b <> ALL
       (
          SELECT b
          FROM another_table
       );

উভয়ই সাধারণত হিসাবে WHERE EXISTSবা একই পরিকল্পনায় অনুকূলিত হয় WHERE NOT EXISTSতবে উদ্দেশ্যটি অনিচ্ছাকৃত এবং আপনার কোনও "অদ্ভুত" 1বা নেই *

মজার বিষয় হল, এর সাথে যুক্ত নাল চেক সমস্যাগুলি NOT IN (...)সমস্যাযুক্ত <> ALL (...), যেখানে সমস্যাগুলি NOT EXISTS (...)ভুগছে না। একটি নল কলাম সহ নিম্নলিখিত দুটি সারণী বিবেচনা করুন:

IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
    DROP TABLE #t;
END;
CREATE TABLE #t 
(
    ID INT NOT NULL IDENTITY(1,1)
    , SomeValue INT NULL
);

IF OBJECT_ID('tempdb..#s') IS NOT NULL
BEGIN
    DROP TABLE #s;
END;
CREATE TABLE #s 
(
    ID INT NOT NULL IDENTITY(1,1)
    , SomeValue INT NULL
);

আমরা দুটোতে কিছু ডেটা যুক্ত করব, কিছু সারি মিলছে এবং কিছু এমন নয় যা:

INSERT INTO #t (SomeValue) VALUES (1);
INSERT INTO #t (SomeValue) VALUES (2);
INSERT INTO #t (SomeValue) VALUES (3);
INSERT INTO #t (SomeValue) VALUES (NULL);

SELECT *
FROM #t;
+ + -------- + + ----------- + +
| আইডি | সামভ্যালু |
+ + -------- + + ----------- + +
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | নুল |
+ + -------- + + ----------- + +
INSERT INTO #s (SomeValue) VALUES (1);
INSERT INTO #s (SomeValue) VALUES (2);
INSERT INTO #s (SomeValue) VALUES (NULL);
INSERT INTO #s (SomeValue) VALUES (4);

SELECT *
FROM #s;
+ + -------- + + ----------- + +
| আইডি | সামভ্যালু |
+ + -------- + + ----------- + +
| 1 | 1 |
| 2 | 2 |
| 3 | নুল |
| 4 | 4 |
+ + -------- + + ----------- + +

NOT IN (...)ক্যোয়ারী:

SELECT *
FROM #t 
WHERE #t.SomeValue NOT IN (
    SELECT #s.SomeValue
    FROM #s 
    );

নিম্নলিখিত পরিকল্পনা আছে:

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

NUL মানগুলি সমতা নিশ্চিত করতে অসম্ভব করে দেওয়ার পরে কোয়েরিতে কোনও সারি নেই।

এই ক্যোয়ারী, <> ALL (...)একই পরিকল্পনাটি দেখায় এবং কোনও সারি দেয় না:

SELECT *
FROM #t 
WHERE #t.SomeValue <> ALL (
    SELECT #s.SomeValue
    FROM #s 
    );

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

বৈকল্পিকটি ব্যবহার করে NOT EXISTS (...)কিছুটা ভিন্ন পরিকল্পনার আকার দেখায় এবং সারিগুলি ফেরত দেয়:

SELECT *
FROM #t 
WHERE NOT EXISTS (
    SELECT 1
    FROM #s 
    WHERE #s.SomeValue = #t.SomeValue
    );

পরিকল্পনা:

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

এই ক্যোয়ারির ফলাফল:

+ + -------- + + ----------- + +
| আইডি | সামভ্যালু |
+ + -------- + + ----------- + +
| 3 | 3 |
| 4 | নুল |
+ + -------- + + ----------- + +

এটি <> ALL (...)যেমন সমস্যাযুক্ত ফলাফলগুলির প্রবণতা তেমনি ব্যবহার করে তোলে NOT IN (...)


3
আমি অবশ্যই বলব যে আমি *অদ্ভুত বলে মনে করি না : আমি EXISTS (SELECT * FROM t WHERE ...) AS পড়ি there is a _row_ in table _t_ that...। যাইহোক, আমি বিকল্প থাকতে চাই, এবং আপনার পরিষ্কারভাবে পঠনযোগ্য। একটি সন্দেহ / সতর্কতা: bঅযোগ্য হলে এটি আচরণ করবে কীভাবে ? [একটি কারণে সৃষ্ট কোনও ভুল ব্যবস্থা খুঁজে বের করার চেষ্টা করার সময় আমার খারাপ অভিজ্ঞতা এবং কিছু ছোট রাত হয়েছিল x IN (SELECT something_nullable FROM a_table)]
jananolo

সারণীতে একটি সারি রয়েছে এবং সত্য বা মিথ্যা প্রত্যাবর্তন করে কিনা তা আপনাকে উপস্থিত রয়েছে tells বিদ্যমান (নির্বাচন থেকে (মান (নাল)) x সত্য। ইন হয় = কোন & না হয় <> সব। এই 4 সম্ভবত মেলে। (এক্স NULLs মানের সঙ্গে একটি RHS সারি নিতে) = কোন (মান (নাল)) & (x) <> সমস্ত (মানগুলি (নাল)) অজানা / নাল তবে বিদ্যমান (মানগুলি (নাল)) সত্য ( ] <> সমস্ত (...) "OR , "কম বিভ্রান্তিকর" নয়
ফিলিপ্সি

@ ফিলিপ্রসি - যদি আমি ভুল হয় তবে এটি স্বীকার করতে আমার কোনও সমস্যা নেই। আপনার নিজের মতো লাগলে নির্দ্বিধায় নিজের উত্তর যুক্ত করুন।
ম্যাক্স ভার্নন

4

"প্রমাণ" যে তারা অভিন্ন (মাইএসকিউএল এ) করতে হবে

EXPLAIN EXTENDED
    SELECT EXISTS ( SELECT * ... ) AS x;
SHOW WARNINGS;

তারপরে পুনরাবৃত্তি করুন SELECT 1। উভয় ক্ষেত্রেই, 'বর্ধিত' আউটপুট দেখায় যে এটি রূপান্তরিত হয়েছিল SELECT 1

একইভাবে, COUNT(*)রূপান্তরিত হয় COUNT(0)

আরেকটি বিষয় লক্ষণীয়: সাম্প্রতিক সংস্করণগুলিতে অনুকূলকরণের উন্নতি করা হয়েছে। এটি EXISTSবনাম বিরোধীদের সাথে তুলনা করার উপযুক্ত হতে পারে । আপনার সংস্করণ অন্যটির তুলনায় একটির সাথে আরও ভাল কাজ করতে পারে।


4

কিছু ডাটাবেসে এই অপ্টিমাইজেশনটি এখনও কাজ করে না। উদাহরণ হিসাবে পোস্টগ্র্রেএসকিউএল 9.6 সংস্করণ অনুসারে, এটি ব্যর্থ হবে।

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

এবং এটি সফল হবে।

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT 1  -- This changed from the first query
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

এটি ব্যর্থ হয়েছে কারণ নিম্নলিখিত ব্যর্থ হয়েছে তবে এর অর্থ এখনও একটি পার্থক্য রয়েছে।

SELECT *
FROM ( VALUES (1),(1) ) AS t(x)
HAVING count(*) > 1;

প্রশ্নের এই উত্তরটিতে আপনি এই নির্দিষ্ট ছটফটানি এবং অনুমানের লঙ্ঘন সম্পর্কে আরও তথ্য পেতে পারেন, এসকিউএল স্পেসের কি উপস্থিতি () দ্বারা গ্রুপের প্রয়োজন?


একটি বিরল কর্নার কেস, সম্ভবত কিছুটা অদ্ভুত , তবে আবারও প্রমাণ করে যে একটি ডাটাবেস ডিজাইনের সময় আপনাকে অনেকগুলি আপস করতে হবে ...
joanolo

-1

আমি সর্বদা ব্যবহার করেছি select top 1 'x'(এসকিউএল সার্ভার)

তাত্ত্বিকভাবে, select top 1 'x'এটি আরও দক্ষ হবে select *যেহেতু প্রাক্তন যোগ্যতার সারিটির অস্তিত্বের উপর ধ্রুবক নির্বাচন করার পরে সম্পূর্ণ হবে, তবে পরেরটি সমস্ত কিছু নির্বাচন করবে।

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


ইন্দ্রিয় তোলে। যে হতে পারে (বা হয়েছে পারে) খুব কম ক্ষেত্রে যেখানে এক top nছাড়া order byএকটি ভাল ধারণা আছে।
joanolo

3
"তাত্ত্বিকভাবে, ...." না, তাত্ত্বিকভাবে কোনও অভিব্যক্তির select top 1 'x'চেয়ে বেশি দক্ষ হওয়া উচিত নয় । ব্যবহারিকভাবে এটি আরও কার্যকর হতে পারে যদি অপ্টিমাইজারটি সাবঅপটিমাল কাজ করে তবে তাত্ত্বিকভাবে উভয় এক্সপ্রেশন সমান হয়। select *Exist
चमत्कार 173

-4

IF EXISTS(SELECT TOP(1) 1 FROMদীর্ঘমেয়াদী এবং প্ল্যাটফর্মগুলি জুড়ে এটি একটি ভাল অভ্যাস যা কেবল আপনার বর্তমান প্ল্যাটফর্ম / সংস্করণটি কতটা ভাল বা খারাপ তা নিয়ে চিন্তা করা শুরু করার প্রয়োজন নেই; এবং এসকিউএল TOP nপ্যারামিটারাইজেবলের দিকে চলেছে TOP(n)। এটি শিখতে হবে একবার দক্ষতা।


3
"প্ল্যাটফর্মগুলি জুড়ে" বলতে আপনার অর্থ কী ? TOPএমনকি বৈধ এসকিউএল নয়।
ypercubeᵀᴹ

"এসকিউএল চলমান .." সরল ভুল। TOP (n)"এসকিউএল" তে কোনও নেই - স্ট্যান্ডার্ড কোয়েরি ভাষা। টি-এসকিউএল-তে একটি রয়েছে যা মাইক্রোসফ্ট এসকিউএল সার্ভারটি উপভাষা ব্যবহার করছে।
a_horse_with_no_name

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