বুলিয়ান এক্সপ্রেশনটি বিপরীত করুন যা অচেনা প্রত্যাবর্তন করতে পারে


11

উদাহরণ

আমার একটা টেবিল আছে

ID  myField
------------
 1  someValue
 2  NULL
 3  someOtherValue

এবং একটি টি এসকিউএল বুলিয়ান এক্সপ্রেশন যা সত্য, মিথ্যা বা (এসকিউএল এর ত্রৈমাসিক যুক্তির কারণে) অজানা:

SELECT * FROM myTable WHERE myField = 'someValue'

-- yields record 1

আমি যদি অন্য সমস্ত রেকর্ড পেতে চাই , আমি কেবল প্রকাশটি অস্বীকার করতে পারি না

SELECT * FROM myTable WHERE NOT (myField = 'someValue')

-- yields only record 3

আমি জানি যে এটি কীভাবে ঘটে (টের্নারি লজিক) এবং আমি জানি যে কীভাবে এই নির্দিষ্ট সমস্যাটি সমাধান করা যায়।

আমি জানি আমি কেবল ব্যবহার করতে পারি myField = 'someValue' AND NOT myField IS NULLএবং আমি একটি "ইনভারটিভেবল" এক্সপ্রেশন পাই যা কখনই অজানা ফল দেয় না:

SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)

-- yields records 2 and 3, hooray!

জেনারেল কেস

এখন, আসুন সাধারণ কেস সম্পর্কে কথা বলা যাক। এর পরিবর্তে myField = 'someValue'আমার কিছু ক্ষেত্র এবং শর্তাদি জড়িত কিছু জটিল ভাব প্রকাশের পরিবর্তে বলুন , সম্ভবত উপশক্তি:

SELECT * FROM myTable WHERE ...some complex Boolean expression...

এই সমাপ্তিটিকে "বিপরীত" করার কোনও সাধারণ উপায় আছে? বোনাস পয়েন্টগুলি যদি এটি সফলতার জন্য কাজ করে:

SELECT * FROM myTable 
 WHERE ...some expression which stays... 
   AND ...some expression which I might want to invert...

আমার এসকিউএল সার্ভার ২০০৮-২০১৪ সমর্থন করতে হবে, তবে ২০০৮ এর চেয়ে বেশি নতুন সংস্করণের প্রয়োজনে যদি একটি দুর্দান্ত সমাধান আসে তবে আমি এটি সম্পর্কে শুনতে আগ্রহী।

উত্তর:


15

আপনি শর্তটি সিএএসই এক্সপ্রেশনতে আবদ্ধ করতে পারেন যা বাইনারি ফলাফল দেয়, উদাহরণস্বরূপ 1 বা 0:

SELECT
  ...
FROM
  ...
WHERE
  CASE WHEN someColumn = someValue THEN 1 ELSE 0 END = 1
;

এক্সপ্রেশন অবহেলা করা আপনাকে একই ডেটা উত্স থেকে সমস্ত অন্যান্য সারি দেবে, যেখানে কোমল কলামটি শূন্য রয়েছে:

SELECT
  ...
FROM
  ...
WHERE
  NOT CASE WHEN someColumn = someValue THEN 1 ELSE 0 END = 1
  -- or: CASE WHEN someColumn = someValue THEN 1 ELSE 0 END <> 1
;

এসকিউএল সার্ভার ২০১২ সাল থেকে আপনার আইআইএফ ফাংশনটিও রয়েছে যা উপরের মত বাইনারি CASE এর চারপাশে কেবল একটি র‍্যাপার। সুতরাং, এই CASE এক্সপ্রেশন:

CASE WHEN someColumn = someValue THEN 1 ELSE 0 END

আইআইএফ ব্যবহার করে নতুন করে লেখা থাকলে এটি এর মতো দেখাবে:

IIF(someColumn = someValue, 1, 0)

এবং আপনি এটিকে ঠিক একইভাবে CASE এক্সপ্রেশন হিসাবে ব্যবহার করতে পারেন। পারফরম্যান্সে কোনও তফাত থাকবে না, কেবল কোডটি আরও কিছুটা সংক্ষিপ্ত হবে, সম্ভবত সেভাবে আরও পরিষ্কার।


এটি একটি দুর্দান্ত ধারণা! বুলিয়ান এক্সপ্রেশনকে "রূপান্তর" করতে সিএসই ব্যবহার করুন যার সাহায্যে এটি কাজ করতে পারে এবং তারপরে "রূপান্তর" করতে তুলনাটি এটি আবার বুলিয়ান এক্সপ্রেশনতে ব্যবহার করুন।
হেইনজি

10

আমার মধ্যে প্রথম চিন্তাটি ঘটে:

DECLARE @T AS table (c1 integer NULL);

INSERT @T (c1)
VALUES (1), (NULL), (2);

-- Original expression c1 = 1
SELECT T.c1
FROM @T AS T
WHERE c1 = 1;

রিটার্নস:

ফলাফল

-- Negated
SELECT T.c1
FROM @T AS T
WHERE NOT EXISTS (SELECT 1 WHERE c1 = 1);

রিটার্নস:

নেতিবাচক ফলাফল

এই নির্ভর উপর উপায় EXISTSসবসময় ফেরৎ সত্য বা মিথ্যা , কখনও অজানা । প্রয়োজনীয়তার SELECT 1 WHEREদুর্ভাগ্যবশত প্রয়োজনীয়, কিন্তু এটি আপনার প্রয়োজন জন্য কার্যকর হতে পারে, উদাহরণস্বরূপ:

sql = "
    SELECT * 
    FROM someTable 
    WHERE " + someExpression + 
    " AND NOT EXISTS (SELECT 1 WHERE " + 
    someOtherExpression + ")";
result = executeAndShow(sql);

উপস্থিতি দেখুন (লেনদেন-এসকিউএল)


কিছুটা জটিল কাজ উদাহরণ যা দেখায় যে কীভাবে EXISTSবা CASE/IIFপদ্ধতি প্রয়োগ করা যেতে পারে পৃথক পূর্বাভাসের জন্য:

DECLARE @T AS table 
(
    c1 integer NULL,
    c2 integer NULL,
    c3 integer NULL
);

INSERT @T 
    (c1, c2, c3)
VALUES 
    (1, NULL, 2),
    (2, 2, 3),
    (NULL, 1, 4);

কোড:

-- Original
SELECT 
    T.c1,
    T.c2,
    T.c3
FROM @T AS T
WHERE
    1 = 1
    -- Predicate #1
    AND T.c1 = 2
    -- Predicate #2
    AND T.c2 =
    (
        SELECT MAX(T2.c2)
        FROM @T AS T2
        WHERE T2.c2 IS NOT NULL
    )
    -- Predicate #3
    AND T.c3 IN (3, 4)
    ;

-- Invert predicates #1 and #2
SELECT 
    T.c1,
    T.c2,
    T.c3
FROM @T AS T
WHERE
    1 = 1
    AND NOT EXISTS (SELECT 1 WHERE 1 = 1
        -- Predicate #1
        AND T.c1 = 2)
    AND NOT EXISTS (SELECT 1 WHERE 1 = 1
        -- Predicate #2
            AND T.c2 =
            (
                SELECT MAX(T2.c2)
                FROM @T AS T2
                WHERE T2.c2 IS NOT NULL
            ))
    -- Predicate #3
    AND T.c3 IN (3, 4)
    ;

3

আপনার সামনে সাব-এক্সপ্রেশনগুলি পুনরায় লেখার বিষয়ে আপত্তি না থাকলে আপনি ব্যবহার করতে পারেন COALESCE:

SELECT *
FROM myTable
WHERE NOT (COALESCE(myField, 'notSomeValue') = 'someValue')

আপনি অবশ্যই'notSomeValue' এটি থেকে পৃথক নিশ্চিত করতে হবে 'someValue'; অগ্রাধিকার হিসাবে, এটি কলামটির জন্য কিছু সম্পূর্ণ অবৈধ মান হবে। (এটি NULLঅবশ্যই হতে পারে না you) আপনার দীর্ঘ তালিকা থাকলেও এটিকে প্রত্যাখ্যান করা সহজ:

SELECT *
FROM myTable
WHERE NOT (
    COALESCE(myField, 'notSomeValue') = 'someValue' AND
    COALESCE(myField2, 'notSomeValue') = 'someValue2' AND
    COALESCE(myField3, 'notSomeValue') = 'someValue3' AND
    COALESCE(myField4, 'notSomeValue') = 'someValue4'
)

ক্লিনার, সহজতর, এবং তুলনায় আরো সুস্পষ্ট CASEবা IIF, আমার মতে। প্রধান নেতিবাচক দিকটি আপনি যে দ্বিতীয় মানটি জানেন তা সমান নয়, তবে আপনি যদি সত্যিকারের সামনের দামটি জানেন না তবে এটি কেবলমাত্র একটি সমস্যা। সেক্ষেত্রে হ্যানো বাইদার যেমন পরামর্শ দেয় এবং ব্যবহার করতে পারে COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'(সেখানে 'someValue'আসলে প্যারামিটারাইজড হবে)।

COALESCE এসকিউএল সার্ভার 2005 থেকে উপলব্ধ হওয়ার জন্য নথিভুক্ত করা হয়েছে।

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


1
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'টেবিলের যে কোনও "সামান্য" এবং কোনও ডেটার জন্য কাজ করা উচিত।
জিমিবি 22'16

2

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

select * from table
except
select * from table
where <really complex predicates>

আসুন আশা করি এটি একটি ছোট টেবিল :-)
লেনার্ট

-4

কোলেসেস পাওয়া যায়?

SELECT * FROM myTable WHERE NOT COALESCE(myField = 'someValue', FALSE)

4
হ্যাঁ, COALESCE উপলভ্য, তবে না, এটি কাজ করবে না: (ক) কলেরসুলি কোনও বুলিয়ান এক্সপ্রেশন গ্রহণ করবে না (কোনওভাবেই চলবে না, ISNULL হবে না) এবং (খ) সত্য মান FALSE এসকিউএল হিসাবে সরাসরি উপলভ্য নয় as একটি আক্ষরিক। এটি ব্যবহার করে দেখুন এবং আপনি একটি সিনট্যাক্স ত্রুটি পাবেন।
হেইনজি

@ হাইঞ্জি - আমি চেষ্টা করেছিলাম, এটি কাজ করেছে, এজন্যই আমি এটি পোস্ট করেছি। হয়তো এটি টি-এসকিউএল-তে কাজ করে না তবে পোস্টগ্রিস এবং মাইএসকিউএলে এটি ঠিক আছে।
মালভোলিও

2
@Malvolio: প্রশ্ন করা হয় বাঁধা sql-server, যদিও, না mysqlবা postgresql
অ্যান্ড্রি এম

@ মালভোলিও কারণ পোস্টগ্র্রেসের একটি BOOLEANটাইপ রয়েছে এবং মাইএসকিউএল এর একটি (নকল) BOOLEANটাইপ রয়েছে যা COALESCE()ফাংশনের পরামিতি হতে পারে। যদি প্রশ্নটি ট্যাগ করা হত sql-agnosticবা sql-standard, উত্তরটি ঠিক ছিল।
ypercubeᵀᴹ

@ ইয়পারক्यूबᵀᴹ - এহ, আমি আপনাকে কী বলতে পারি? একটি ভাল ডাটাবেস পান।
মালভোলিও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.