चर के रूप में केस स्टेटमेंट में 100 से अधिक प्रविष्टियां कैसे हैं


11

मैंने> 100 विकल्पों के साथ एक केस स्टेटमेंट लिखा जहां मैं एक साधारण क्वेरी में 4 स्थानों पर एक ही स्टेटमेंट का उपयोग कर रहा हूं।

उनके बीच एक संघ के साथ एक ही क्वेरी दो बार लेकिन एक गिनती भी कर रही है और इसलिए समूह द्वारा भी केस स्टेटमेंट शामिल है।

यह कुछ कंपनी के नामों को रीलैब करने के लिए है जहां एक ही कंपनी के लिए अलग-अलग रिकॉर्ड अलग-अलग तरीके से लिखे गए हैं।

मैंने एक चर को चर (मैक्स) घोषित करने की कोशिश की

declare @CaseForAccountConsolidation varchar(max)

SET @CaseForAccountConsolidation = 'CASE 
       WHEN ac.accountName like ''AIR NEW Z%'' THEN ''AIR NEW ZEALAND''
       WHEN ac.accountName LIKE ''AIR BP%'' THEN ''AIR BP''
       WHEN ac.accountName LIKE ''ADDICTION ADVICE%'' THEN ''ADDICTION ADVICE''
       WHEN ac.accountName LIKE ''AIA%'' THEN ''AIA''
       ...

जब मैं इसे अपने चुनिंदा स्टेटमेंट में इस्तेमाल करने गया - तो क्वेरी ने केस स्टेटमेंट को टेक्स्ट के रूप में लौटाया और उसका मूल्यांकन नहीं किया।

मैं भी समूह में इसका उपयोग करने में असमर्थ था - मुझे यह त्रुटि संदेश मिला:

Each GROUP BY expression must contain at least one column that is not an outer reference.

आदर्श रूप में मैं केवल एक ही स्थान पर CASE करना चाहूंगा - ताकि मुझे एक पंक्ति को अपडेट करने और उस अन्य जगह की नकल न करने का कोई मौका न हो।

क्या ऐसा करने का कोई तरीका है?

मैं अन्य तरीकों से खुला हूं (जैसे शायद कोई फ़ंक्शन - लेकिन मुझे यकीन नहीं है कि उन्हें इस तरह कैसे उपयोग करना है)

यहाँ अभी मैं जो SELECT का उपयोग कर रहा हूँ उसका एक नमूना है

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END AS accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = CONVERT(DATE,now())
GROUP BY
   dl.FirstDateOfMonth
   ,dl.FinancialYear
   ,dl.FirstDateOfWeek
   ,CONVERT(Date,c.date_charged)
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END

UNION

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END AS accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
GROUP BY
   dl.FirstDateOfMonth
   ,dl.FinancialYear
   ,dl.FirstDateOfWeek
   ,CONVERT(Date,c.date_charged)
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END

इस UNION का उद्देश्य एक टाइमपरोड के लिए सभी डेटा को वापस करना है, और ALSO को उसी टाइमस्पिरोड के लिए डेटा को 12 महीने पहले वापस करना है।

संपादित करें: एक लापता "CATCH-ALL"
EDIT2 जोड़ा गया: UNION कथन का एक दूसरा second जोड़ा गया
EDIT3: कुछ अन्य आवश्यक तत्वों को शामिल करने के लिए समूह द्वारा सही किया गया


UNION के 2 भाग कैसे भिन्न होते हैं? वे समान रूप से समान दिखते हैं, सिवाय थोड़ी भिन्न स्थितियों के।
ypercube y

यही प्रमुख अंतर है। आज की तारीख में दो अलग-अलग शर्तें जहां और 12 महीने पहले की ही तारीख हैं। इसका मतलब है कि मैं उस दिन और उसी दिन के लिए संख्याओं की तुलना 12 महीने पहले प्रस्तुति परत में कर सकता हूं - लेकिन एकल SQL क्वेरी चला रहा हूं।
kiltannen

3
क्यों नहीं एक एकल के साथ का चयन करें WHERE a.datecreated = CONVERT(DATE,now()) OR a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))?
ypercube y

@ ypercube y इसका सरल उत्तर यह है कि जब मैं पहली बार इसका निर्माण कर रहा था, तो मैं इसे कहीं और कर रहा था जिसने UNION का उपयोग किया। थोड़ा और अधिक जटिल यह है कि तारीख सीमा वास्तव में आज की तुलना में काफी अधिक जटिल है और 12 महीने पहले एक ही तारीख है। मैं जिस तिथि सीमा का चयन कर रहा हूं, वह 1 जुलाई से वर्तमान तिथि + से पहले 1 जुलाई तक है, जो कि ठीक 12 महीने पहले की तारीख है। (वित्तीय वर्ष वी.एस. लास्ट फाइनेंशियल वाईटीडी १२ महीने पहले - यह वृद्धि की तुलना करता है या अन्यथा वित्तीय वर्ष के लिए)। लेकिन एंड्री के रूप में BUT और आप सुझाव देते हैं, मैं माइनस द यूनिअन की कोशिश करने जा रहा हूं
kiltannen

जवाबों:


11

CASE अभिव्यक्ति की पुनरावृत्ति को खत्म करने का एक आसान तरीका है, इस तरह से CROSS APPLY का उपयोग करना:

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,x.accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   CROSS APPLY
   (
    SELECT 
       CASE 
           WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
           WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
           WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
           WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       END AS accountName
   ) AS x
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
GROUP BY
   dl.FirstDateOfMonth
   ,x.AccountName

CROSS APPLY की मदद से आप अपने CASE एक्सप्रेशन के लिए एक नाम इस तरह से असाइन करते हैं कि इसे आपके स्टेटमेंट में कहीं भी संदर्भित किया जा सके। यह काम करता है क्योंकि कड़ाई से बोलते हुए आप एक नेस्टेड में गणना किए गए कॉलम को परिभाषित कर रहे हैं चयन - FROM-less SELECT जो CROSS APPLY का अनुसरण करता है।

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

यूनिअन क्वेरी के लिए जो उसी CASE अभिव्यक्ति का उपयोग करता है, आपको इसे प्रत्येक पैर में परिभाषित करना होगा, इसके लिए कोई समाधान नहीं है सिवाय इसके कि CASE के बजाय पूरी तरह से अलग प्रतिस्थापन विधि का उपयोग करें। हालाँकि, आपके विशिष्ट मामले में बिना UNION के परिणाम प्राप्त करना संभव है।

दोनों पैर केवल WHERE की स्थिति में भिन्न होते हैं। एक यह है:

WHERE a.datecreated = CONVERT(DATE,now())

और यह अन्य:

WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))

आप उन्हें इस तरह से जोड़ सकते हैं:

WHERE a.datecreated IN (
                        CONVERT(DATE,now()),
                        DATEADD(YEAR,-1,CONVERT(DATE,now()))
                       )

और इस उत्तर की शुरुआत में संशोधित चयन पर लागू करें।


अच्छा एंड्री - +1! आपके द्वारा प्रेरित :-), मैंने अपने उत्तर में एक और दृष्टिकोण जोड़ा है - एक CTE- मुझे यकीन नहीं है कि सबसे अच्छा तरीका कौन सा है!
वेयर्स

हाय एंड्री, मुझे इस समाधान का रूप पसंद है। मैंने उल्लेख किया कि मेरे पास एक संघ था - लेकिन मैं अपने उदाहरण में इसे शामिल नहीं करने के लिए पर्याप्त गूंगा था। मैंने अब किया है। मुझे यह संदेह है कि CROSS APPLY से इस x को UNION के दूसरे भाग में उपलब्ध होने की संभावना नहीं है? तो इसका मतलब यह होगा कि मैं अभी भी CASE की 2 प्रतियों के साथ फंस जाऊंगा क्या यह सही है? (जब मैं काम पर वापस
जाऊंगा

@kiltannen ड्रॉप करें UNIONऔर बस datecreatedकॉलम को अपने GROUP BYखंड में शामिल करें (और उस WHEREखंड को अपडेट करें जिसमें आप रुचि रखते हैं दोनों तिथियों को शामिल करें)।
स्कॉट एम

@ एसटीएमटीएम: मुझे नहीं लगता कि ओपी datecreatedको ग्रुप बीवाई में कॉलम को शामिल करने की आवश्यकता है । इसके अलावा, मैं पूरी तरह से सहमत हूं, वे सिर्फ जहां को जोड़ सकते हैं और संघ को खोद सकते हैं।
एंड्री एम

@ scott-m मुझे यह कल करने की कोशिश करनी होगी लेकिन मुझे संदेह है कि इतनी अच्छी तरह से काम नहीं करता है। यह वास्तव में एक दिन नहीं है - यह संभावित रूप से कई महीने है। मुझे लगता है कि मैं दैनिक डेटा के 11 महीने तक चला था - तो जहां शुरुआत और अंत था और फिर मुझे 12 महीने पहले उसी अवधि के लिए एक OR चलाना पड़ा। मुझे लगता है कि यह एक प्रदर्शन हिट के साथ समाप्त हुआ। मुझे फिर से प्रयास करना होगा - लेकिन मुझे याद है कि उन समस्याओं में भाग लेना जो मेरे पास नहीं थी जब मैं UNION चला रहा था। बेशक यह खुद की समस्याओं को लाता है। जैसे मैं वर्तमान में कुश्ती कर रहा हूँ ..
kiltannen

22

डेटा को एक तालिका में रखें

CREATE TABLE AccountTranslate (wrong VARCHAR(50), translated(VARCHAR(50));

INSERT INTO AccountTranslate VALUES ('ADDICTION ADVICE%','ADDICTION ADVICE');
INSERT INTO AccountTranslate VALUES ('AIR BP%','AIR BP');
INSERT INTO AccountTranslate VALUES ('AIR NEW Z%', 'AIR NEW ZEALAND');

और इसमें शामिल हों।

SELECT ...,COALESCE(AccountTranslate.translated, ac.accountName) AS accountName
FROM
...., 
account_code ac left outer join 
AccountTranslate at on ac.accountName LIKE AccountTranslate.wrong

इस तरह आप कई स्थानों पर डेटा को अद्यतित रखने से बच सकते हैं। COALESCEजहां जरूरत हो बस वहीं इस्तेमाल करें । आप इसे VIEWअन्य सुझावों के अनुसार सीटीई या एस में शामिल कर सकते हैं।


4

एक अन्य विकल्प मुझे लगता है कि अगर आपको इसे फिर से उपयोग करने की आवश्यकता है तो कई स्थानों पर एक इनलाइन टेबल वैल्यू फ़ंक्शन एक अच्छा होगा।

CREATE FUNCTION dbo.itvf_CaseForAccountConsolidation
    ( @au_lname VARCHAR(8000) ) 
RETURNS TABLE 
RETURN 
SELECT  
  CASE
    WHEN UPPER(@au_lname) LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
    WHEN UPPER(@au_lname) LIKE 'AIR BP%'  THEN 'AIR BP'
    WHEN UPPER(@au_lname) LIKE 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
    ELSE '****ERROR****'  -- you may or may not need this! 
                         -- If converting every record, then yes, if not, then no!
                         -- Errors should stand out on browsing and it's easy to search for!
  END AS wrong

--Copied from verace

आपका चयन इस तरह होगा।

  SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,dd.wrong AS accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
   CROSS APPLY  dbo.itvf_CaseForAccountConsolidation( ac.accountName)dd
GROUP BY
   dl.FirstDateOfMonth 
   ,dl.FirstDateOfWeek 
   ,wrong 
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged)

साथ ही, मैंने इसका परीक्षण नहीं किया है और कोड का प्रदर्शन भी निर्धारित किया जाना चाहिए।

EDIT1 : मैं एंड्री पहले से ही लगता है कि एक जो का उपयोग करता है को पार होता है कि कौन कोड को संशोधित कर दिया है। खैर, इस एक को केंद्रीकृत किया जा सकता है क्योंकि फ़ंक्शन में कोई भी परिवर्तन सभी में प्रतिबिंबित होगा क्योंकि आप कोड के अन्य भागों में समान दोहरा रहे हैं।


3

मैं एक VIEWका उपयोग करने के लिए आप क्या करने की कोशिश कर रहे हैं। आप निश्चित रूप से अंतर्निहित डेटा को सही कर सकते हैं, लेकिन अक्सर इस साइट पर, सवाल पूछने वाले (सलाहकार / dbas /) ऐसा करने का अधिकार नहीं रखते हैं। A का उपयोग करके VIEWइस समस्या को हल किया जा सकता है! मैंने UPPERफ़ंक्शन का उपयोग भी किया - इस तरह के मामलों में त्रुटियों को हल करने का एक सस्ता तरीका।

अब, आप केवल VIEWएक बार घोषणा करते हैं और कहीं भी इसका उपयोग कर सकते हैं! इस तरह, आपके पास केवल एक स्थान है जिसमें आपका डेटा रूपांतरण एल्गोरिथ्म संग्रहीत और चलाया जाता है, जिससे आपके सिस्टम की विश्वसनीयता और मजबूती बढ़ जाती है।

आप CTE ( कॉमन टेबल एक्सप्रेशन ) का उपयोग भी कर सकते हैं - उत्तर के नीचे देखें!

आपके प्रश्न का उत्तर देने के लिए, मैंने निम्नलिखित कार्य किया:

एक नमूना तालिका बनाएँ:

CREATE TABLE my_error (wrong VARCHAR(50));

नमूना रिकॉर्ड के एक जोड़े डालें:

INSERT INTO my_error VALUES ('Addiction Advice Services Ltd.');
INSERT INTO my_error VALUES ('AIR BP_and-mistake');
INSERT INTO my_error VALUES ('AIR New Zealand Airlines');

फिर VIEWसुझाव के अनुसार बनाएं :

CREATE VIEW my_error_view AS 
SELECT 
  CASE
    WHEN UPPER(wrong) LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
    WHEN UPPER(wrong) LIKE 'AIR BP%'  THEN 'AIR BP'
    WHEN UPPER(wrong) LIKE 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
    ELSE '***ERROR****' -- You may or may not need this.
                        -- It's attention grabbing (report) and easy to search for (SQL)!
  END AS wrong
FROM my_error;

फिर, SELECT अपने से VIEW:

SELECT * FROM my_error_view
ORDER BY wrong;

परिणाम:

ADDICTION ADVICE
AIR BP
AIR NEW ZEALAND

Et voilà!

यह सब आपको यहां की बेला पर मिल सकता है

CTEदृष्टिकोण:

ऊपर के रूप में एक ही है, को छोड़कर निम्नानुसार CTEप्रतिस्थापित VIEWहै:

WITH my_cte AS
(
  SELECT 
  CASE
    WHEN UPPER(wrong) LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
    WHEN UPPER(wrong) LIKE 'AIR BP%'  THEN 'AIR BP'
    WHEN UPPER(wrong) LIKE 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
    ELSE '****ERROR****'  -- you may or may not need this! 
                         -- If converting every record, then yes, if not, then no!
                         -- Errors should stand out on browsing and it's easy to search for!
  END AS wrong
  FROM my_error
)
SELECT * FROM my_cte;

नतीजा वही है। तब CTEआप किसी भी अन्य तालिका के रूप में इलाज कर सकते हैं - SELECTकेवल एस के लिए ! यहाँ उपलब्ध फिडल ।

कुल मिलाकर, मुझे लगता है कि VIEWइस मामले में दृष्टिकोण बेहतर है!


0

एंबेडेड टेबल

select id, tag, trans.val 
  from [consecutive] c
  join ( values ('AIR NEW Z%', 'AIR NEW ZEALAND'),
                ('AIR BP%',    'AIR BP')
       ) trans (lk, val)
    on c.description like trans.lk 

संघ को छोड़ें और ORदूसरों द्वारा सुझाए गए अनुसार उपयोग करें ।

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