संदर्भ उपनाम (जिसमें चयन में गणना की गई है) कहां है


130
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE BalanceDue > 0 --error

चयनित कॉलम की सूची में एक चर के रूप में सेट की गई गणना मान 'BalanceDue' का उपयोग WHERE क्लॉज में नहीं किया जा सकता है।

वहाँ एक रास्ता है कि यह कर सकता है? इस संबंधित प्रश्न में ( MySQL सिलेक्ट स्टेटमेंट में एक वेरिएशन इन अ क्लॉज का उपयोग करते हुए ), ऐसा लगता है जैसे उत्तर होगा, वास्तव में, नहीं, आप बस गणना लिखेंगे ( और क्वेरी में उस गणना को निष्पादित करें) दो बार, इनमें से कोई नहीं जो संतोषजनक है।

जवाबों:


237

आप ORDER BY को छोड़कर किसी अन्य को संदर्भित नहीं कर सकते क्योंकि SELECT दूसरा अंतिम खंड है जिसका मूल्यांकन किया गया है। दो वर्कअराउंड:

SELECT BalanceDue FROM (
  SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
  FROM Invoices
) AS x
WHERE BalanceDue > 0;

या बस अभिव्यक्ति को दोहराएं:

SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE  (InvoiceTotal - PaymentTotal - CreditTotal)  > 0;

मैं बाद वाला पसंद करता हूं। यदि अभिव्यक्ति अत्यंत जटिल है (या गणना करने के लिए महंगा) तो आपको शायद इसके बजाय एक गणना किए गए कॉलम (और शायद लगातार) पर विचार करना चाहिए, खासकर यदि बहुत सारे प्रश्न इसी अभिव्यक्ति का संदर्भ देते हैं।

पुनश्च आपका डर निराधार लग रहा है। कम से कम इस सरल उदाहरण में, SQL सर्वर केवल एक बार गणना करने के लिए पर्याप्त स्मार्ट है, भले ही आपने इसे दो बार संदर्भित किया हो। आगे बढ़ो और योजनाओं की तुलना करो; आप देखेंगे कि वे समान हैं। यदि आपके पास एक अधिक जटिल मामला है जहां आप कई बार मूल्यांकन किए गए अभिव्यक्ति को देखते हैं, तो कृपया अधिक जटिल क्वेरी और योजनाओं को पोस्ट करें।

यहां 5 उदाहरण प्रश्न दिए गए हैं, जो सभी समान निष्पादन योजना प्रस्तुत करते हैं:

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE LEN(name) + column_id > 30;

SELECT x FROM (
SELECT LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE column_id + LEN(name) > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE LEN(name) + column_id > 30;

सभी पांच प्रश्नों के लिए परिणामी योजना:

यहाँ छवि विवरण दर्ज करें


11
वाह। SQL सर्वर केवल एक बार गणना करने के लिए पर्याप्त स्मार्ट है
वैकल्पिक

5
वाह यह एक बहुत ही उच्च गुणवत्ता का जवाब!
सिद्धार्थ

मुझे MERGE स्टेटमेंट में कुछ अतिरिक्त शर्तों की आवश्यकता थी, और यह एकमात्र तरीका था जिससे मैं इसे काम कर सकता था। धन्यवाद!
एरिक बर्डो

1
@ EricBurdo यदि आप उपयोग कर रहे हैं MERGE, तो कृपया सुनिश्चित करें कि आपने यह सब ध्यान में रखा है: MERGEसावधानी के साथ
हारून बर्ट्रेंड

11

आप इस का उपयोग कर सकते हैं cross apply

SELECT c.BalanceDue AS BalanceDue
FROM Invoices
cross apply (select (InvoiceTotal - PaymentTotal - CreditTotal) as BalanceDue) as c
WHERE  c.BalanceDue  > 0;

4

यह वास्तव में एक चर को प्रभावी ढंग से परिभाषित करना संभव है जो कि SELECT, WHERE और अन्य क्लॉज़ दोनों में उपयोग किया जा सकता है।

एक क्रॉस ज्वाइन जरूरी रूप से संदर्भित टेबल कॉलम के लिए उचित बाध्यकारी के लिए अनुमति नहीं देता है, हालांकि OUTER APPLY करता है - और पारदर्शी रूप से नल का इलाज करता है।

SELECT
    vars.BalanceDue
FROM
    Entity e
OUTER APPLY (
    SELECT
        -- variables   
        BalanceDue = e.EntityTypeId,
        Variable2 = ...some..long..complex..expression..etc...
    ) vars
WHERE
    vars.BalanceDue > 0

करने के लिए कुडोस सैयद Mehroz आलम

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.