এসকিউএল সার্ভার যদি প্রথম যুক্তিটি নাল না হয় তবেও একটি COALESCE ফাংশন সমস্ত পড়ে?


98

আমি একটি টি-এসকিউএল COALESCEফাংশন ব্যবহার করছি যেখানে এটি প্রথম চালানো প্রায় 95% বারে প্রথম যুক্তি বাতিল হবে না। যদি প্রথম যুক্তিটি হয় NULLতবে দ্বিতীয় যুক্তিটি বেশ দীর্ঘ প্রক্রিয়া:

SELECT COALESCE(c.FirstName
                ,(SELECT TOP 1 b.FirstName
                  FROM TableA a 
                  JOIN TableB b ON .....)
                )

যদি, উদাহরণস্বরূপ, c.FirstName = 'John'এসকিউএল সার্ভারটি কি এখনও সাব-কোয়েরি চালাবে?

আমি VB.NET IIF()ফাংশন দিয়ে জানি , যদি দ্বিতীয় তর্কটি সত্য হয় তবে কোডটি তৃতীয় আর্গুমেন্টটি পড়বে (যদিও এটি ব্যবহৃত হবে না)।

উত্তর:


95

নাহ । এখানে একটি সহজ পরীক্ষা:

SELECT COALESCE(1, (SELECT 1/0)) -- runs fine
SELECT COALESCE(NULL, (SELECT 1/0)) -- throws error

যদি দ্বিতীয় শর্তটি মূল্যায়ন করা হয়, তবে একটি ব্যতিক্রম শূন্য বিভাজনের জন্য ছুঁড়ে দেওয়া হবে।

প্রতি MSDN ডকুমেন্টেশন এই কিভাবে সম্পর্কযুক্ত COALESCEদোভাষীর মধ্য দেখা হয় - এটা শুধু একটি সহজ উপায় একটি লিখতে এর CASEবিবৃতি।

CASE এসকিউএল সার্ভারের একমাত্র ফাংশন হিসাবে সুপরিচিত যা (বেশিরভাগ) নির্ভরযোগ্যভাবে শর্ট সার্কিট।

কিছু ব্যতিক্রম যখন যেমন হারুন বারট্রান্ড দ্বারা প্রদর্শিত অন্য উত্তর এখানে স্কালে ভেরিয়েবল এবং aggregations তুলনায় (এবং এই উভয় ক্ষেত্রে প্রযোজ্য যাবে CASEএবং COALESCE):

DECLARE @i INT = 1;
SELECT CASE WHEN @i = 1 THEN 1 ELSE MIN(1/0) END;

শূন্য ত্রুটির দ্বারা একটি বিভাগ তৈরি করবে।

এটি একটি ত্রুটি হিসাবে বিবেচনা করা উচিত এবং একটি নিয়ম হিসাবে COALESCEবাম থেকে ডানে পার্স করা হবে।


6
@ জেএনকে দয়া করে একটি সহজ সরল কেসটি দেখার জন্য আমার উত্তরটি দেখুন যেখানে এটি সত্য হয় না (আমার উদ্বেগের বিষয় আরও অনেক বেশি, এখনও CASEঅব্যাহত পরিস্থিতিতে রয়েছে - এটি সর্বদা বাম-থেকে-ডান এবং সর্বদা সংক্ষিপ্ত সার্কিটের মূল্যায়ন করে তা সম্মত করা শক্ত করে তোলে) )।
অ্যারন বারট্র্যান্ড

4
অন্যান্য আকর্ষণীয় আচরণ @ এসকিউএলকিউই আমাকে উল্লেখ করেছেন: SELECT COALESCE((SELECT CASE WHEN RAND() <= 0.5 THEN 1 END), 1);- একাধিকবার পুনরাবৃত্তি করুন। আপনি NULLমাঝে মাঝে পাবেন। এর সাথে আবার চেষ্টা করুন ISNULL- আপনি কখনই পাবেন না NULL...
অ্যারন বারট্রান্ড


@ মার্টিন হ্যাঁ আমিও বিশ্বাস করি। তবে আচরণটি নয় যা বেশিরভাগ ব্যবহারকারীরা সমস্যাটি শুনে (বা কামড় দিয়েছিল) না শুনলে স্বজ্ঞাত মনে করবে।
অ্যারন বারট্র্যান্ড

73

কীভাবে এটি সম্পর্কে - যেমনটি ইজজিক বেন-গান আমাকে জানিয়েছিল, যাকে জায়েম লাফারগু বলেছিল ?

DECLARE @i INT = 1;
SELECT CASE WHEN @i = 1 THEN 1 ELSE MIN(1/0) END;

ফলাফল:

Msg 8134, Level 16, State 1, Line 2
Divide by zero error encountered.

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

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

ডকুমেন্টেশনে বর্ণিত হিসাবে আপনি সাধারণতCASE বাম থেকে ডান এবং শর্ট সার্কিটের মূল্যায়নের উপর নির্ভর করতে পারেন, আপনি সর্বদা এটি করতে পারবেন তা বলা সঠিক নয় not এই পৃষ্ঠায় দুটি প্রদর্শিত মামলা আছে যেখানে এটি সত্য নয় এবং এসকিউএল সার্ভারের কোনও প্রকাশ্যে উপলভ্য সংস্করণে বাগও ঠিক করা হয়নি।

এখানে সম্পাদনা হ'ল আরও একটি কেস (আমার তা করা বন্ধ করা দরকার) যেখানে CASEকোনও সংখ্যক জড়িত না থাকা সত্ত্বেও কোনও অভিব্যক্তি আপনার প্রত্যাশা অনুযায়ী ক্রম মূল্যায়ন করে না।


2
এবং দেখে মনে হচ্ছে এটির সাথে আরও একটি সমস্যা রয়েছে CASE যা নিঃশব্দে স্থির হয়েছে
মার্টিন স্মিথ

আইএমও এটি প্রমাণ করে না যে CASE এক্সপ্রেশনটির মূল্যায়ন গ্যারান্টিযুক্ত নয় কারণ নির্বাচনের আগে সমষ্টিগত মানগুলি গণনা করা হয় (যাতে তারা থাকার অভ্যন্তরে ব্যবহার করতে পারে)।
সালমান এ

1
@ সালমানা আমি নিশ্চিত নই যে এটি সম্ভবত কোনও ঘটনাই প্রমাণ করে ব্যতীত সিএসই-র মত প্রকাশের মূল্যায়নের ক্রমটি নিশ্চিত নয়। আমরা একটি ব্যতিক্রম পাচ্ছি কারণ সমষ্টিটি প্রথমে গণনা করা হয়, যদিও এটি কোনও ELSE ধারায় রয়েছে যে - আপনি যদি ডকুমেন্টেশনটিতে যান - কখনও পৌঁছানো উচিত নয়।
অ্যারন বারট্র্যান্ড

@ অ্যারনবার্ট্রান্ডের সমষ্টিগুলি CASE স্টেটমেন্টের আগে গণনা করা হয় (এবং তাদের আইএমও করা উচিত)। সংশোধিত ডকুমেন্টেশন হুবহু এটিকে নির্দেশ করে, সিএএসই মূল্যায়নের আগে ত্রুটি ঘটে ।
সালমান এ

@ সালমানা এটি এখনও নৈমিত্তিক বিকাশকারীকে দেখিয়েছে যে সিএসই এক্সপ্রেশনটি যেভাবে লেখা হয়েছিল তাতে মূল্যায়ন করে না - অন্তর্নিহিত যান্ত্রিকগুলি অপ্রাসঙ্গিক যদি আপনি যা করার চেষ্টা করছেন তা যদি বোঝা যায় যে কোনও সিএসই শাখা থেকে একটি ত্রুটি কেন আসছে যা উচিত নয় ' টি পৌঁছেছে। আপনি কি এই পৃষ্ঠায় অন্যান্য সমস্ত উদাহরণ বিরুদ্ধে যুক্তি আছে?
অ্যারন বারট্র্যান্ড

37

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

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

মূল প্রশ্নের সাথে সম্পর্কিত, CASE- এর সাথে অন্যান্য সমস্যা রয়েছে (এবং তাই COALESCE) যেখানে পার্শ্ব-কার্যকারী ফাংশন বা উপ-প্রশ্নগুলি ব্যবহৃত হয়। বিবেচনা:

SELECT COALESCE((SELECT CASE WHEN RAND() <= 0.5 THEN 999 END), 999);
SELECT ISNULL((SELECT CASE WHEN RAND() <= 0.5 THEN 999 END), 999);

COALESCE ফর্মটি প্রায়শই NULL ফেরত দেয়, আরও বিশদ https://connect.microsoft.com/SQLServer/feedback/details/546437/coalesce-subquery-1-may-return-null এ

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

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

আমার ধারণা, একটি অত্যন্ত সন্তোষজনক রাষ্ট্র নয়।


18

আমি অন্য একটি ক্ষেত্রে এসেছি যেখানে CASE/ COALESCEশর্ট সার্কিট নয়। 1প্যারামিটার হিসাবে পাস করা হলে নিম্নলিখিত টিভিএফ একটি পিকে লঙ্ঘন উত্থাপন করবে

CREATE FUNCTION F (@P INT)
RETURNS @T TABLE (
  C INT PRIMARY KEY)
AS
  BEGIN
      INSERT INTO @T
      VALUES      (1),
                  (@P)

      RETURN
  END

যদি নীচে বলা হয়

DECLARE @Number INT = 1

SELECT COALESCE(@Number, (SELECT number
                          FROM   master..spt_values
                          WHERE  type = 'P'
                                 AND number = @Number), 
                         (SELECT TOP (1)  C
                          FROM   F(@Number))) 

বা হিসাবে

DECLARE @Number INT = 1

SELECT CASE
         WHEN @Number = 1 THEN @Number
         ELSE (SELECT TOP (1) C
               FROM   F(@Number))
       END 

উভয়ই ফলাফল দেয়

প্রাথমিক কেই বাধা 'PK__F__3BD019A800551192' লঙ্ঘন। 'Dbo। @ T' অবজেক্টে সদৃশ কী sertোকানো যায় না। সদৃশ কী মানটি (1)।

দেখানো হচ্ছে যে SELECT(বা কমপক্ষে টেবিলের পরিবর্তনশীল জনসংখ্যা) এখনও চালিত হয়েছে এবং ত্রুটি উত্থাপন করে যদিও বিবৃতিটির সেই শাখাটি কখনই পৌঁছানো উচিত নয়। COALESCEসংস্করণটির পরিকল্পনা নীচে রয়েছে is

পরিকল্পনা

কোয়েরির এই পুনর্লিখনটি সমস্যাটি এড়াতে উপস্থিত হবে

SELECT COALESCE(Number, (SELECT number
                          FROM   master..spt_values
                          WHERE  type = 'P'
                                 AND number = Number), 
                         (SELECT TOP (1)  C
                          FROM   F(Number))) 
FROM (VALUES(1)) V(Number)   

যা পরিকল্পনা দেয়

Plan2


8

আরেকটি উদাহরণ

CREATE TABLE T1 (C INT PRIMARY KEY)

CREATE TABLE T2 (C INT PRIMARY KEY)

INSERT INTO T1 
OUTPUT inserted.* INTO T2
VALUES (1),(2),(3);

ক্যোয়ারী

SET STATISTICS IO ON;

SELECT T1.C,
       COALESCE(T1.C , CASE WHEN EXISTS (SELECT * FROM T2 WHERE T2.C = T1.C)  THEN -1 END)
FROM T1
OPTION (LOOP JOIN)

মোটেও কোনও পাঠ্য দেখায় না T2

এর চাইতে T2সম্পৃক্ত মাধ্যমে একটি পাস করা হচ্ছে এবং অপারেটর মৃত্যুদন্ড কার্যকর করা হয় না। কিন্তু

SELECT T1.C,
       COALESCE(T1.C , CASE WHEN EXISTS (SELECT * FROM T2 WHERE T2.C = T1.C)  THEN -1 END)
FROM T1
OPTION (MERGE JOIN)

কি শো T2পড়া হয়। যদিও কোন মূল্য থেকে T2আসলে কখনও প্রয়োজন হয় না।

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


7

আমি কেবল এমন একটি কৌশল উল্লেখ করতে চেয়েছিলাম যা আপনি বিবেচনা করতে পারেন নি। এটি এখানে ম্যাচ নাও হতে পারে তবে এটি কখনও কখনও কাজে আসে। দেখুন এই পরিবর্তনটি আপনাকে আরও ভাল পারফরম্যান্স দেয় কিনা:

SELECT COALESCE(c.FirstName
            ,(SELECT TOP 1 b.FirstName
              FROM TableA a 
              JOIN TableB b ON .....
              WHERE C.FirstName IS NULL) -- this is the changed part
            )

এটি করার আরেকটি উপায় এটি হতে পারে (মূলত সমতুল্য, তবে প্রয়োজন হলে অন্যান্য ক্যোয়ারী থেকে আরও কলামগুলি অ্যাক্সেসের অনুমতি দেয়):

SELECT COALESCE(c.FirstName, x.FirstName)
FROM
   TableC c
   OUTER APPLY (
      SELECT TOP 1 b.FirstName
      FROM
         TableA a 
         JOIN TableB b ON ...
      WHERE
         c.FirstName IS NULL -- the important part
   ) x

মূলত এটি "শক্ত" যোগদানের টেবিলগুলির একটি কৌশল কিন্তু কখন কোনও সারি যুক্ত হওয়া উচিত তার শর্তটি অন্তর্ভুক্ত করে। আমার অভিজ্ঞতায় এটি সময়ে সময়ে বাস্তবায়নের পরিকল্পনাগুলিতে সত্যই সহায়তা করে।


3

না, এটা হবে না। এটি কেবল তখনই c.FirstNameচলত NULL

তবে আপনার নিজেরাই এটি চেষ্টা করা উচিত। পরীক্ষা। আপনি বলেছিলেন যে আপনার সাবকিউরিটি দীর্ঘ। মাপকাঠি. এটিতে আপনার নিজস্ব সিদ্ধান্ত আঁকুন।

চলমান সাব-কোয়েরিতে @ অ্যারন উত্তরটি আরও সম্পূর্ণ।

তবে আমি এখনও মনে করি আপনার জিজ্ঞাসা এবং ব্যবহারটি পুনরায় করা উচিত LEFT JOIN। বেশিরভাগ সময় সাব-কোয়েরি ব্যবহার করে আপনার ক্যোয়ারীটি পুনরায় কাজ করে মুছে ফেলা যায় LEFT JOIN

সাব-কোয়েরি ব্যবহারে সমস্যাটি হ'ল আপনার সামগ্রিক বিবৃতিটি ধীরে চলবে কারণ উপ-ক্যোয়ারির মূল ক্যোয়ারির ফলাফল সেটে প্রতিটি সারির জন্য রান করা হয়।


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

3

প্রকৃত স্ট্যান্ডার্ডটি বলে যে পুরোটা প্রকাশের অভিব্যক্তির ডেটা ধরণ নির্ধারণ করতে WHEN দফা (সেইসাথে ELSE ধারা) সমস্তগুলি বিশ্লেষণ করতে হবে। ত্রুটি কীভাবে পরিচালনা করা হয় তা নির্ধারণ করতে আমার সত্যিই আমার কিছু পুরানো নোট বের করতে হবে। তবে ঠিক হাতের মুঠোয়, 1/0 পূর্ণসংখ্যা ব্যবহার করে, তাই আমি ধরে নেব যে এটি একটি ত্রুটি থাকা অবস্থায়। এটি পূর্ণসংখ্যা ডেটা টাইপের সাথে একটি ত্রুটি। যখন আপনার কেবল কোলেসেস তালিকায় শূন্য থাকে তখন ডেটা টাইপ নির্ধারণ করা একটু কৌশলযুক্ত এবং এটি অন্য সমস্যা trick

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