कॉमन टेबल एक्सप्रेशन (CTE) का उपयोग कब करें


230

मैंने कॉमन टेबल एक्सप्रेशन के बारे में पढ़ना शुरू कर दिया है और एक ऐसे उपयोग के मामले के बारे में नहीं सोच सकता, जहां मुझे उनका उपयोग करने की आवश्यकता होगी। वे निरर्थक प्रतीत होंगे क्योंकि व्युत्पन्न तालिकाओं के साथ भी ऐसा ही किया जा सकता है। क्या कुछ ऐसा है जो मुझे याद आ रहा है या अच्छी तरह से समझ नहीं रहा है? क्या कोई मुझे CTE का मामला बनाने के लिए नियमित चयन, व्युत्पन्न या अस्थायी तालिका प्रश्नों की सीमाओं का एक सरल उदाहरण दे सकता है? किसी भी सरल उदाहरण अत्यधिक सराहना की जाएगी।

जवाबों:


197

एक उदाहरण, यदि आपको CTE को परिभाषित करके ऐसा करने के लिए एक ही डेटा सेट को कई बार संदर्भित / शामिल करना है। इसलिए, यह कोड री-यूज़ का एक रूप हो सकता है।

आत्म संदर्भित का एक उदाहरण पुनरावृत्ति है: CTE का उपयोग करके पुनरावर्ती क्वेरी

रोमांचक Microsoft परिभाषाओं के लिए ऑनलाइन पुस्तकों से लिया गया:

CTE का उपयोग किया जा सकता है:

  • एक पुनरावर्ती क्वेरी बनाएँ। अधिक जानकारी के लिए, सामान्य तालिका अभिव्यक्तियों का उपयोग करके पुनरावर्ती क्वेरी देखें

  • किसी दृश्य के सामान्य उपयोग की आवश्यकता नहीं होने पर देखने के लिए स्थानापन्न; यही है, आपको मेटाडेटा में परिभाषा को संग्रहीत करने की आवश्यकता नहीं है।

  • एक स्तंभ, जो एक स्केलर सबसेलेक्ट, या एक फ़ंक्शन से लिया गया है, जो या तो नियतात्मक नहीं है या बाहरी पहुंच है, द्वारा समूहीकरण को सक्षम करें।

  • परिणामी तालिका को एक ही कथन में कई बार देखें।


7
हां। आप एक व्युत्पन्न तालिका में शामिल नहीं हो सकते। इस बात को ध्यान में रखते हुए कि CTE में एक सेल्फ जॉइन अभी भी आपको इसके 2 अलग-अलग इनवॉइस के साथ छोड़ देगा।
मार्टिन स्मिथ

@ मर्टिन - मैं हैरान हूं। क्या आप उस कथन का समर्थन कर सकते हैं?
रिचर्ड द किवी

@ जॉन धन्यवाद, मुझे 4guysfromrolla.com/webtech/071906-1.shtml काफी उपयोगी लग रही है
im

4
@ बर्बरकीवी - कौन सा? कि एक स्व शामिल होने से 2 अलग-अलग आह्वान होंगे? इस उत्तर में उदाहरण देखें stackoverflow.com/questions/3362043/…
मार्टिन स्मिथ

4
CTE के बारे में रोचक तथ्य मुझे हमेशा आश्चर्य होता है कि CTE के एक बार से अधिक संदर्भित होने पर CTE में NEWID () क्यों बदल जाता है। select top 100 * into #tmp from master..spt_values order by 1,2,3,4 select A.number, COUNT(*) from #tmp A inner join #tmp B ON A.number = B.number+1 group by A.numberबनामwith CTE AS (select top 100 * from master..spt_values order by 1,2,3,4) select A.number, COUNT(*) from CTE A inner join CTE B ON A.number = B.number+1 group by A.number
रिचर्ड द किवी

50

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

उनके बारे में मेरी केवल यही शिकायत है कि उनका दोबारा इस्तेमाल नहीं किया जा सकता। उदाहरण के लिए, मेरे पास दो अपडेट स्टेटमेंट के साथ एक संग्रहित खरीद हो सकती है जो एक ही सीटीई का उपयोग कर सकती है। लेकिन सीटीई की 'गुंजाइश' केवल पहली क्वेरी है।

मुसीबत है, 'सरल उदाहरण' शायद वास्तव में सीटीई की जरूरत नहीं है!

फिर भी, बहुत काम।


ठीक है। क्या आप कुछ अपेक्षाकृत जटिल उदाहरण के साथ मामला बना सकते हैं जो इस अवधारणा के आसपास मेरे सिर की मदद कर सकते हैं?
imak

28
"उनके बारे में मेरी एकमात्र शिकायत यह है कि उनका फिर से उपयोग नहीं किया जा सकता" - एक सीटीई जिसे आप फिर से उपयोग करना चाहते हैं, उसे एक उम्मीदवार के लिए माना जाना चाहिए VIEW:)
onedaywhen

6
@onedaywhen: समझ में आया, लेकिन इसका मतलब है कि एक वैश्विक-गुंजाइश जिसका मैं हमेशा सहज नहीं हूं। कभी-कभी एक खरीद के दायरे में मैं एक सीटीई को परिभाषित करना चाहता हूं और इसे चयन और अपडेट के लिए उपयोग करता हूं, या विभिन्न तालिकाओं से समान डेटा का चयन करता हूं।
n8wrl

5
जब मुझे एक से अधिक बार एक ही सीटीई की आवश्यकता होती है, तो मैं इसे एक अस्थायी तालिका में खिलाता हूं और फिर अस्थायी तालिका का उपयोग करता हूं जितना मैं चाहता हूं।
फैंडैंगो 68

43

Cte's का उपयोग करने के दो कारण हैं।

जहाँ खंड में परिकलित मान का उपयोग करने के लिए। यह एक व्युत्पन्न तालिका की तुलना में मुझे थोड़ा साफ लगता है।

मान लीजिए कि दो तालिकाएँ हैं - प्रश्न और उत्तर, प्रश्न = उत्तर = उत्तर से जुड़े हुए हैं। प्रश्न_आदि (और प्रश्नोत्तरी आईडी)

WITH CTE AS
(
    Select Question_Text,
           (SELECT Count(*) FROM Answers A WHERE A.Question_ID = Q.ID) AS Number_Of_Answers
    FROM Questions Q
)
SELECT * FROM CTE
WHERE Number_Of_Answers > 0

यहाँ एक और उदाहरण है जहाँ मैं प्रश्नों और उत्तरों की एक सूची प्राप्त करना चाहता हूँ। मैं चाहता हूं कि उत्तरों को परिणामों में प्रश्नों के साथ समूहीकृत किया जाए।

WITH cte AS
(
    SELECT [Quiz_ID] 
      ,[ID] AS Question_Id
      ,null AS Answer_Id
          ,[Question_Text]
          ,null AS Answer
          ,1 AS Is_Question
    FROM [Questions]

    UNION ALL

    SELECT Q.[Quiz_ID]
      ,[Question_ID]
      ,A.[ID] AS  Answer_Id
      ,Q.Question_Text
          ,[Answer]
          ,0 AS Is_Question
        FROM [Answers] A INNER JOIN [Questions] Q ON Q.Quiz_ID = A.Quiz_ID AND Q.Id = A.Question_Id
)
SELECT 
    Quiz_Id,
    Question_Id,
    Is_Question,
    (CASE WHEN Answer IS NULL THEN Question_Text ELSE Answer END) as Name
FROM cte    
GROUP BY Quiz_Id, Question_Id, Answer_id, Question_Text, Answer, Is_Question 
order by Quiz_Id, Question_Id, Is_Question Desc, Name

10
क्या आपका पहला उदाहरण CTE के बजाय केवल नेस्टेड क्वेरी का उपयोग करने के लिए सरल नहीं किया जा सकता है?
सैम

2
दोनों उदाहरण हो सकते हैं।
मनाची

3
आपको सीटीई के बिना पहले एक को जोड़ना चाहिए, फिर यह तुरंत स्पष्ट है कि उत्तरार्द्ध उपयोगी क्यों है।
उफोस

HAVINGएक और तरीका है एक अंतिम अवस्था फिल्टर जो एक उप उपयोग करने के समान हो सकता है ऐसा करने के लिए हैSELECT
विलियम Entriken

21

CTE का उपयोग करने के लिए उपयोगी परिदृश्यों में से एक है जब आप एक या अधिक स्तंभों के आधार पर डेटा की DISTINCT पंक्तियाँ प्राप्त करना चाहते हैं, लेकिन तालिका में सभी कॉलम लौटाते हैं। एक मानक क्वेरी के साथ, आपको पहले अलग-अलग मानों को एक अस्थायी तालिका में डंप करना होगा और फिर उन्हें बाकी स्तंभों को पुनः प्राप्त करने के लिए मूल तालिका में वापस शामिल करने का प्रयास करना होगा या आप एक अत्यंत जटिल विभाजन क्वेरी लिख सकते हैं जिसमें परिणाम वापस आ सकते हैं एक रन लेकिन अधिकांश संभावना में, यह अपठनीय होगा और प्रदर्शन का कारण बन सकता है।

लेकिन सीटीई का उपयोग करके (जैसा कि एक रिकॉर्ड के पहले उदाहरण का चयन करने पर टिम श्मेल्टर द्वारा उत्तर दिया गया है )

WITH CTE AS(
    SELECT myTable.*
    , RN = ROW_NUMBER()OVER(PARTITION BY patientID ORDER BY ID)
    FROM myTable 
)
SELECT * FROM CTE
WHERE RN = 1

जैसा कि आप देख सकते हैं, यह पढ़ना और बनाए रखना बहुत आसान है। और अन्य प्रश्नों की तुलना में, प्रदर्शन में बहुत बेहतर है।


16

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

  • एक पुनरावर्ती क्वेरी बनाएँ।
  • अपनी क्वेरी में CTE के परिणाम को एक से अधिक बार उपयोग करें।
  • समान क्वेरी के बड़े हिस्से को कम करके अपनी क्वेरी में स्पष्टता को बढ़ावा दें।
  • CTE के परिणाम में प्राप्त एक कॉलम द्वारा समूहीकरण सक्षम करें

यहाँ एक कट और पेस्ट उदाहरण के साथ खेलने के लिए है:

WITH [cte_example] AS (
SELECT 1 AS [myNum], 'a num' as [label]
UNION ALL
SELECT [myNum]+1,[label]
FROM [cte_example]
WHERE [myNum] <=  10
)
SELECT * FROM [cte_example]
UNION
SELECT SUM([myNum]), 'sum_all' FROM [cte_example]
UNION
SELECT SUM([myNum]), 'sum_odd' FROM [cte_example] WHERE [myNum] % 2 = 1
UNION
SELECT SUM([myNum]), 'sum_even' FROM [cte_example] WHERE [myNum] % 2 = 0;

का आनंद लें


7

आज हम कॉमन टेबल एक्सप्रेशन के बारे में जानने जा रहे हैं जो कि एक नई सुविधा है जिसे SQL सर्वर 2005 में पेश किया गया था और बाद के संस्करणों में भी उपलब्ध है।

सामान्य टेबल एक्सप्रेशन: - कॉमन टेबल एक्सप्रेशन को एक अस्थायी परिणाम सेट के रूप में या दूसरे शब्दों में SQL सर्वर में विचारों का एक विकल्प के रूप में परिभाषित किया जा सकता है। सामान्य तालिका अभिव्यक्ति केवल उस कथन के बैच में मान्य होती है जहाँ इसे परिभाषित किया गया था और अन्य सत्रों में इसका उपयोग नहीं किया जा सकता है।

CTE (सामान्य तालिका अभिव्यक्ति) घोषित करने का सिंटैक्स: -

with [Name of CTE]
as
(
Body of common table expression
)

एक उदाहरण लेते हैं: -

CREATE TABLE Employee([EID] [int] IDENTITY(10,5) NOT NULL,[Name] [varchar](50) NULL)

insert into Employee(Name) values('Neeraj')
insert into Employee(Name) values('dheeraj')
insert into Employee(Name) values('shayam')
insert into Employee(Name) values('vikas')
insert into Employee(Name) values('raj')

CREATE TABLE DEPT(EID INT,DEPTNAME VARCHAR(100))
insert into dept values(10,'IT')
insert into dept values(15,'Finance')
insert into dept values(20,'Admin')
insert into dept values(25,'HR')
insert into dept values(10,'Payroll')

मैंने दो टेबल कर्मचारी और विभाग बनाए हैं और प्रत्येक तालिका में 5 पंक्तियाँ डाली हैं। अब मैं इन तालिकाओं में शामिल होना चाहता हूं और इसे आगे उपयोग करने के लिए एक अस्थायी परिणाम तैयार करना चाहता हूं।

With CTE_Example(EID,Name,DeptName)
as
(
select Employee.EID,Name,DeptName from Employee 
inner join DEPT on Employee.EID =DEPT.EID
)
select * from CTE_Example

एक-एक करके स्टेटमेंट के प्रत्येक लाइन को लें और समझें।

CTE को परिभाषित करने के लिए हम "क्लॉज़" के साथ लिखते हैं, फिर हम टेबल एक्सप्रेशन को एक नाम देते हैं, यहाँ मैंने "CTE_Example" नाम दिया है

फिर हम "अस" लिखते हैं और अपने कोड को दो कोष्ठक (---) में संलग्न करते हैं, हम संलग्न कोष्ठक में कई तालिकाओं में शामिल हो सकते हैं।

अंतिम पंक्ति में, मैंने CTE_Example से "Select *" का उपयोग किया है, हम कोड की अंतिम पंक्ति में कॉमन टेबल एक्सप्रेशन का उल्लेख कर रहे हैं, इसलिए हम कह सकते हैं कि इसका एक दृश्य जैसा है, जहाँ हम एक में दृश्य को परिभाषित और उपयोग कर रहे हैं बैच और CTE को स्थायी ऑब्जेक्ट के रूप में डेटाबेस में संग्रहीत नहीं किया जाता है। लेकिन यह एक दृश्य की तरह व्यवहार करता है। हम CTE पर डिलीट और अपडेट स्टेटमेंट कर सकते हैं और इसका सीधा असर उस टेबल पर पड़ेगा, जो CTE में इस्तेमाल की जा रही है। इस तथ्य को समझने के लिए एक उदाहरण लेते हैं।

With CTE_Example(EID,DeptName)
as
(
select EID,DeptName from DEPT 
)
delete from CTE_Example where EID=10 and DeptName ='Payroll'

उपरोक्त कथन में हम CTE_Example से एक पंक्ति हटा रहे हैं और यह CTE में उपयोग की जा रही संदर्भित तालिका "DEPT" से डेटा को हटा देगा।


मुझे अभी भी बात नहीं मिली। इसके बीच अंतर क्या है और सिर्फ डीईपीटी से हटाए जाने की स्थिति समान है? यह कुछ भी आसान बनाने के लिए प्रतीत नहीं होता है।
होल्गर जेकब्स

कृपया मुझे सही करें अगर मैं गलत हूं, लेकिन निष्पादन योजना अलग हो सकती है, और मुझे लगता है कि नीरज की बात है, कि एक ही उद्देश्य को प्राप्त करने के कई तरीके हैं, लेकिन कुछ को स्थिति के आधार पर दूसरों पर लाभ होगा। उदाहरण के लिए, कुछ परिस्थितियों में DELETE FROM स्टेटमेंट पर CTE को पढ़ना आसान हो सकता है, दूसरों में रिवर्स भी सही हो सकता है। प्रदर्शन में सुधार या खराब हो सकता है। आदि
WonderWorker

7

जब आप "ऑर्डर किया गया अपडेट" करना चाहते हैं तो यह बहुत उपयोगी है।

MS SQL आपको UPDATE के साथ ORDER BY का उपयोग करने की अनुमति नहीं देता है, लेकिन CTE की मदद से आप इसे इस तरह से कर सकते हैं:

WITH cte AS
(
    SELECT TOP(5000) message_compressed, message, exception_compressed, exception
    FROM logs
    WHERE Id >= 5519694 
    ORDER BY Id
)
UPDATE  cte
SET     message_compressed = COMPRESS(message), exception_compressed = COMPRESS(exception)

अधिक जानकारी के लिए यहां देखें: ms sql का उपयोग करके कैसे अपडेट और ऑर्डर करें


0

एक बिंदु अभी तक नहीं बताया गया है, गति है । मुझे पता है कि यह एक पुराना उत्तर दिया गया प्रश्न है, लेकिन मुझे लगता है कि यह प्रत्यक्ष टिप्पणी / उत्तर का हकदार है:

वे निरर्थक प्रतीत होंगे क्योंकि व्युत्पन्न तालिकाओं के साथ भी ऐसा ही किया जा सकता है

जब मैंने CTE का पहली बार उपयोग किया तो मैं इसकी गति से बिल्कुल स्तब्ध था। यह एक पाठ्यपुस्तक की तरह एक मामला था, सीटीई के लिए बहुत उपयुक्त, लेकिन सभी महासागरों में मैंने कभी भी सीटीई का इस्तेमाल किया, एक महत्वपूर्ण गति प्राप्त हुई। मेरी पहली क्वेरी व्युत्पन्न तालिकाओं के साथ जटिल थी, जिसे निष्पादित करने में लंबा समय लगा। CTE के साथ इसने कुछ सेकंड्स के फ्रैक्शंस को लिया और मुझे हैरान कर दिया, कि यह संभव है।


-4
 ;with cte as
  (
  Select Department, Max(salary) as MaxSalary
  from test
  group by department
  )  
  select t.* from test t join cte c on c.department=t.department 
  where t.salary=c.MaxSalary;

इसे इस्तेमाल करे

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