2016-08-31 19 views
5

trying to make a Slick query more readable का एक परिणाम के रूप में, मैं इस प्रश्न के निर्माता है, जो काम करता हैइन दो स्लिम प्रश्नों के बराबर क्यों नहीं हैं?

val q = Users.filter(_.id === userId) join People on { 
    case (u, p) => u.personId === p.id 
} joinLeft Addresses on { 
    case ((u, p), a) => p.addressId === a.id 
} joinLeft Businesses on { 
    case (((u, p), a), b) => p.businessId === b.id 
} joinLeft Addresses on { 
    case ((((u, p), a), b), ba) => b.flatMap(_.addressId) === ba.id 
} map { 
    case ((((u, p), a), b), ba) => (p, a, b, ba) 
} 

और यह एक मैंने सोचा था कि बराबर होगा है, लेकिन काम नहीं करता:

val q = Users.filter(_.id === userId) join People joinLeft Addresses joinLeft Businesses joinLeft Addresses on { 
    case ((((u, p), a), b), ba) => 
    u.personId === p.id && 
    p.addressId === a.flatMap(_.id) && 
    p.businessId === b.flatMap(_.id) && 
    b.flatMap(_.addressId) === ba.id 
} map { 
    case ((((u, p), a), b), ba) => (p, a, b, ba) 
} 

दूसरा एक प्रतीत होता है प्रोफाइल की एक सूची लौट रहे हैं जिसमें लक्ष्य एक से अधिक शामिल है।

वे समान क्यों नहीं हैं?


"बराबर" एसक्यूएल (आईई इस निर्माण के लक्ष्य) है:

select p.*, a1.*, b.*, a2.* from Users u 
innerJoin People p on (u.personId == p.id) 
leftJoin Addresses a1 on (p.addressId == a1.id) 
leftJoin Businesses b on (p.businessId == b.id) 
leftJoin Addresses a2 on (b.addressId == a2.id) 

उत्तर

3

समस्या यहाँ है, slick uses a LiteralNode(true) as the default join condition. तो दूसरा क्वेरी होगा कुछ में परिणाम ऐसा दिखाई देता है:

select p.*, a1.*, b.*, a2.* 
    from Users u 
    join People p on 1 = 1 
left join Addresses a1 on 1 = 1 
left join Businesses b on 1 = 1 
left join Addresses a2 on u.personId = p.id 
         and p.addressId = a1.id 
         and p.businessId = b.id 
         and b.addressId = a2.id 

जैसा कि आप देख सकते हैं, सभी स्थितियों में शामिल होने वाली सभी स्थितियों में शामिल होने की अपेक्षा की जाने वाली सभी स्थितियां वास्तव में अंतिम शामिल होने की स्थिति में शामिल हैं।

को समझने के लिए कि यह कैसे अंतिम परिणाम को प्रभावित करेगा, की समस्या के रूप में निम्नानुसार को आसान बनाने में करते हैं:

create temporary table A (id int primary key); 

insert into A values (1), (2); 

    select a1.id, a2.id, a3.id 
    from A a1 
    join A a2 on 1 = 1 
left join A a3 on a1.id = a2.id 
       and a2.id = a3.id; 

पहले के आधार पर संयोजन, A1 और A2 एक शर्त है कि हमेशा सच है, एक अस्थायी परिणाम में जिसके परिणामस्वरूप द्वारा शामिल हो गए हैं का:

(1, 1) 
(1, 2) 
(2, 1) 
(2, 2) 

अब दूसरे शामिल होने पर विचार करें। हमारे पास स्थिति में शामिल होने के हिस्से के रूप में a1.id = a2.id है, लेकिन याद रखें कि शामिल होने की स्थिति का उपयोग यह तय करने के लिए किया जाता है कि टेबल ए 3 से पंक्तियों को कैसे प्राप्त किया जाए, पहले शामिल होने के मध्यवर्ती परिणाम को फ़िल्टर न करें। और हम यहां एक बाएं शामिल हो रहे हैं, इसलिए एनयूएलएल की अतिरिक्त ए 3 पंक्ति उत्पन्न होती है, भले ही जॉइन की स्थिति संतुष्ट न हो। अंतिम परिणाम हो जाएगा:

(1, 1, 1) 
(1, 2, NULL) 
(2, 1, NULL) 
(2, 2, 2) 

तो, आप पिछले बाईं शामिल हो गए तालिका शून्य होने का कॉलम के साथ एक बहुत अधिक अप्रत्याशित परिणाम देखने के लिए उम्मीद कर रहे हैं।

संबंधित मुद्दे