लारवेल क्वेरी बिल्डर का उपयोग करके उपकुंजी से चयन कैसे करें?


102

मैं निम्नलिखित SQL द्वारा Eloquent ORM का उपयोग करके मूल्य प्राप्त करना चाहूंगा।

- एसक्यूएल

 SELECT COUNT(*) FROM 
 (SELECT * FROM abc GROUP BY col1) AS a;

तब मैंने निम्नलिखित पर विचार किया।

- कोड

 $sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
 $num = Abc::from(\DB::raw($sql))->count();
 print $num;

मैं एक बेहतर समाधान की तलाश में हूं।

कृपया मुझे सबसे सरल उपाय बताएं।

जवाबों:


133

@ डेलमॉर्ड के उत्तर और आपकी टिप्पणियों के अलावा:

वर्तमान में FROMउपवाक्य बनाने की कोई विधि नहीं है , इसलिए आपको मैन्युअल रूप से कच्चे विवरण का उपयोग करने की आवश्यकता है, फिर, यदि आवश्यक हो, तो आप सभी बाइंडिंग को मर्ज करेंगे:

$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
    ->count();

मन जिसे आपको सही क्रम में बाइंडिंग को मर्ज करने की आवश्यकता है । यदि आपके पास अन्य बाध्य खंड हैं, तो आपको उन्हें रखना चाहिए mergeBindings:

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )

    // ->where(..) wrong

    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder

    // ->where(..) correct

    ->count();

3
ध्यान दें कि यदि आपके पास एक जटिल क्वेरी के रूप में एक belongsToManygetQuery()$sub->getQuery()->getQuery()
अवचेतन के

1
@Skyzer आप जो मैं लिख रहे हैं वह नहीं पढ़ रहे हैं। जब आप कॉल करते हैं तो कुछ भी नहीं बच जाता है toSql। पीडीओ php.net/manual/en/book.pdo.php के बारे में पढ़ें और अपना परिणाम देखें$query->toSql()
Jarek Tkaczyk

5
के संबंध में -> मर्जबिंडिंग्स ($ उप-> गेटिवा ()) बस करो -> मर्जबिंडिंग्स ($ उप)
जिमी इलेनॉला

1
@JimmyIlenloa यदि $subक्वेरी एलोकेंट बिल्डर है , तो आपको अभी भी ->getQuery()भाग की आवश्यकता है , अन्यथा आपको त्रुटि मिलती है, क्योंकि यह विधि Query\Builderवर्ग के विरुद्ध टाइप की गई है ।
जारेक टाकज़ीक

1
@ कन्नन नप। यह मेरे द्वारा अनुमान लगाए गए पीआर के लिए एक उम्मीदवार है, लेकिन अंत में यह बहुत सामान्य उपयोग का मामला नहीं है। संभवतः आज तक वहां नहीं होने का यही कारण है ..
Jarek Tkaczyk

79

Laravel v5.6.12 (2018-03-14) जोड़ा गया fromSub()और fromRaw()बिल्डर को क्वेरी करने के तरीके (# 23476)

स्वीकृत उत्तर सही है लेकिन इसमें सरल किया जा सकता है:

DB::query()->fromSub(function ($query) {
    $query->from('abc')->groupBy('col1');
}, 'a')->count();

उपरोक्त स्निपेट निम्न SQL का उत्पादन करता है:

select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`

16

@JarekTkaczyk का समाधान वास्तव में वही है जिसकी मुझे तलाश थी। केवल एक चीज मुझे याद आती है कि यह कैसे करना है जब आप DB::table()प्रश्नों का उपयोग कर रहे हैं । इस मामले में, यह है कि मैं इसे कैसे करता हूं:

$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
    'something', 
    DB::raw('sum( qty ) as qty'), 
    'foo', 
    'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();

विधि mergeBindingsका उपयोग किए बिना कैसे बनाने के लिए विशेष ध्यानgetQuery()


का उपयोग करते हुए DB::raw()मेरे लिए काम किया था
नीनो Škopac

7

लार्वा 5.5 से उपश्रेणियों के लिए एक समर्पित तरीका है और आप इसे इस तरह से उपयोग कर सकते हैं:

Abc::selectSub(function($q) {
    $q->select('*')->groupBy('col1');
}, 'a')->count('a.*');

या

Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');

1
ऐसा लगता है कि SubSelect का उपयोग केवल SEL में उप क्वेरी जोड़ने के लिए किया जा सकता है, FROM से नहीं।
हागाबाक

1
Call to undefined method subSelect()ऐसा लगता है जैसे subSelectमौजूद नहीं है।
मारूफ अलोम

3
इसे मेरे संज्ञान में लाने के लिए धन्यवाद, मुझे नाम याद है, यह होना चाहिए था selectSub। मैंने अपनी प्रतिक्रिया अब अपडेट कर दी है।
सासा ब्लैगोजेविक

3

मुझे ऐसा कुछ करना पसंद है:

Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
                  WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
                  GROUP BY `from_id` asc) as `sub`"))
->count();

यह बहुत सुरुचिपूर्ण नहीं है, लेकिन यह सरल है।


धन्यवाद यह मेरे लिए काम किया, एक साइड नोट के रूप में, चयन सामग्री से सावधान रहें क्योंकि लार्वा ने कुछ उद्धरण चिह्नों को जोड़ा और मुझे उनसे छुटकारा पाने के लिए -> चयन (\ DB :: कच्चा ('आपका चयन')) का उपयोग करना पड़ा।
Wak

2

मैं वांछित क्वेरी करने के लिए आपका कोड नहीं बना सका, एएस केवल तालिका के लिए एक उपनाम है abc, न कि व्युत्पन्न तालिका के लिए। लारवेल क्वेरी बिल्डर व्युत्पन्न तालिका उपनामों का समर्थन नहीं करता है, डीबी :: कच्चे इसके लिए सबसे अधिक आवश्यक है।

सबसे सीधा समाधान जो मैं आपके साथ आ सकता था, वह आपके लिए लगभग समान है, हालांकि आपके द्वारा पूछे जाने पर क्वेरी उत्पन्न करता है:

$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();

उत्पादित क्वेरी है

select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;

आपके जवाब के लिए धन्यवाद। "एबीसी :: से (???) और डीबी :: टेबल (???)" की विधि में एक समस्या है। $ sql = Abc :: जहाँ ('id', '=', $ id) -> groupBy ('col1') -> toSql (); $ गिनती = DB :: तालिका (DB :: कच्ची ("($ sql) AS")) -> गिनती (); SQL त्रुटि उपरोक्त कोड में होती है। - कहाँ और पैरामीटर असाइन करें!
quenty658

2

इस उत्तर में वर्णित सही तरीका: https://stackoverflow.com/a/52772444/2519714 वर्तमान समय में सबसे लोकप्रिय उत्तर पूरी तरह से सही नहीं है।

इस तरह https://stackoverflow.com/a/24838367/2519714 कुछ मामलों में सही नहीं है जैसे: सब सिलेक्ट में जहां बाइंडिंग है, फिर टेबल को सब सेलेक्ट करने के लिए ज्वाइन करना है, तो अन्य व्हाट्स को सभी क्वेरी में जोड़ा गया है। उदाहरण के लिए क्वेरी: select * from (select * from t1 where col1 = ?) join t2 on col1 = col2 and col3 = ? where t2.col4 = ? इस क्वेरी को बनाने के लिए आप कोड लिखेंगे जैसे:

$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->from(DB::raw('('. $subQuery->toSql() . ') AS subquery'))
    ->mergeBindings($subQuery->getBindings());
$query->join('t2', function(JoinClause $join) {
    $join->on('subquery.col1', 't2.col2');
    $join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');

इस क्वेरी को निष्पादित करने के दौरान, उनका तरीका $query->getBindings()गलत क्रम में बाइंडिंग लौटाएगा , जैसे कि ऊपर वर्णित कच्चे sql के लिए ['val3', 'val1', 'val4']सही ['val1', 'val3', 'val4']है।

ऐसा करने का एक और सही समय:

$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->fromSub($subQuery, 'subquery');
$query->join('t2', function(JoinClause $join) {
    $join->on('subquery.col1', 't2.col2');
    $join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');

इसके अलावा बाइंडिंग स्वचालित रूप से और सही ढंग से नई क्वेरी में विलय हो जाएगी।


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