दूसरा उत्तर पहले से ही काफी लंबा है, इसलिए मैं इसे वैसे ही छोड़ रहा हूं। यह उत्तर बहुत बेहतर, सरल और सही भी है जबकि दूसरे में कुछ किनारे-मामले हैं जो गलत उत्तर देंगे - मैं उस अभ्यास को पाठक पर छोड़ दूंगा।
नोट:स्पष्टता के लिए लाइन ब्रेक जोड़े गए हैं। संपूर्ण ब्लॉक एक ही प्रश्न है
;with Walker(StartX,StartY,X,Y,Visited) as (
select X,Y,X,Y,CAST('('+right(X,3)+','+right(Y,3)+')' as Varchar(Max))
from puzzle
union all
select W.StartX,W.StartY,P.X,P.Y,W.Visited+'('+right(P.X,3)+','+right(P.Y,3)+')'
from Walker W
join Puzzle P on
(W.X=P.X and W.Y=P.Y+1 OR -- these four lines "collect" a cell next to
W.X=P.X and W.Y=P.Y-1 OR -- the current one in any direction
W.X=P.X+1 and W.Y=P.Y OR
W.X=P.X-1 and W.Y=P.Y)
AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
)
select X, Y, Visited
from
(
select W.X, W.Y, W.Visited, rn=row_number() over (
partition by W.X,W.Y
order by len(W.Visited) desc)
from Walker W
left join Walker Other
on Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
where Other.X is null
) Z
where rn=1
पहला कदम एक "वॉकर" रिकर्सिव टेबल एक्सप्रेशन स्थापित करना है जो हर सेल से शुरू होगा और बिना किसी कदम को पीछे हटाए जितना हो सके यात्रा करेगा। यह सुनिश्चित करना कि कक्षों का पुनरीक्षण नहीं किया जाता है, विज़िट किए गए कॉलम का उपयोग करके किया जाता है, जो प्रत्येक प्रारंभिक बिंदु से देखे गए प्रत्येक कक्ष को संग्रहीत करता है। विशेष रूप से, यह स्थिति AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
उन कक्षों को अस्वीकार करता है जिन्हें वह पहले ही देख चुका है।
यह समझने के लिए कि बाकी कैसे काम करता है, आपको सीटीई के बाद "वाकर" सीटीई द्वारा "स्टार्टएक्स, स्टार्टवाई द्वारा वॉकर ऑर्डर से चयन करें" चलाकर उत्पन्न परिणाम को देखना होगा। 5 कोशिकाओं वाला एक "टुकड़ा" कम से कम 5 समूहों में दिखाई देता है, प्रत्येक एक अलग (StartX,StartY)
के साथ , लेकिन प्रत्येक समूह में सभी 5 (X,Y)
. हैं अलग-अलग "विज़िट" पथ वाले टुकड़े।
सबक्वेरी (Z) स्थिति द्वारा परिभाषित "प्रथम XY निर्देशांक" वाले प्रत्येक समूह में एकल पंक्ति तक समूहों को कम करने के लिए LEFT JOIN + IS NULL का उपयोग करता है
Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
इरादा प्रत्येक सेल के लिए है जिसे (स्टार्टएक्स, स्टार्टवाई) से शुरू किया जा सकता है, एक ही समूह में एक दूसरे सेल के खिलाफ तुलना करने के लिए, और उस सेल को खोजने के लिए जहां कोई अन्य सेल उच्च पंक्ति पर नहीं है, या यदि वे पर हैं वही पंक्ति, इस सेल के बाईं ओर है। हालाँकि, यह अभी भी हमें बहुत अधिक परिणाम देता है। (3,4) और (4,4):
. पर केवल 2-सेल टुकड़े पर विचार करेंStartX StartY X Y Visited
3 4 3 4 (3,4) ******
3 4 4 4 (3,4)(4,4)
4 4 4 4 (4,4)
4 4 3 4 (4,4)(3,4) ******
2 पंक्तियाँ "पहले XY निर्देशांक" (3,4) के साथ रहती हैं, जो ******
. से चिह्नित होती हैं . हमें केवल एक पंक्ति की आवश्यकता है, इसलिए हम Row_Number का उपयोग करते हैं और चूंकि हम क्रमांकन कर रहे हैं, इसलिए हम सबसे लंबे समय तक Visited
के लिए भी जा सकते हैं पथ, जो हमें जितना देगा टुकड़े के भीतर की कोशिकाओं को हम प्राप्त कर सकते हैं।
अंतिम बाहरी क्वेरी बस प्रत्येक समान (X,Y) समूह से पहली पंक्तियाँ (RN=1) लेती है।
प्रत्येक टुकड़े के सभी सेल दिखाने के लिए, लाइन बदलेंselect X, Y, Visited
बीच में
select X, Y, (
select distinct '('+right(StartX,3)+','+right(StartY,3)+')'
from Walker
where X=Z.X and Y=Z.Y
for xml path('')
) PieceCells
जो यह आउटपुट देते हैं
X Y PieceCells
1 1 (1,1)(2,1)(2,2)(3,2)
3 4 (3,4)(4,4)
5 6 (5,6)
7 5 (7,5)(8,5)(9,5)
8 1 (10,1)(8,1)(8,2)(9,1)(9,2)(9,3)