2014-10-27 8 views
5

मैं PHP और MySQL का उपयोग करके एक गतिशील क्वेरी बनाने की कोशिश कर रहा हूं।फ़ील्ड की सूची से गतिशील क्वेरी कैसे बनाएं?

मैंने क्या किया एक मेज बनाई गई है (यानी। field_relations) इस क्षेत्र 5 स्तंभ

  1. FIELD_NAME (एक क्षेत्र का नाम है "यानी। ACCOUNT_ID, account_name ....") है
  2. display_label (वैसे कैसे क्षेत्र उपयोग करने के लिए विस्थापित किया जाना चाहिए "यानी। खाता क्रमांक, नाम")
  3. TABLE_NAME (टेबल जहां इस क्षेत्र के लिए "अर्थात्। खाते" हैं)
  4. related_to (करने के लिए क्षेत्र के संबंध एक अलग तालिका "अगर कोई है।" डिफ़ॉल्ट मान 0 है)
  5. related_to_field (क्षेत्र जहां यह कहते हैं करने के लिए "यदि कोई हो।" डिफ़ॉल्ट मान अगर मैं 3 के साथ एक HTML प्रपत्र बनाने NULL)

यहाँ एक नमूना डेटा field_name display_label table_name related_to related_to_field account_id Account ID accounts NULL NULL account_name Name accounts NULL NULL first_name First Name contacts NULL NULL last_name Last Name contacts NULL NULL contact_id Contact ID contacts NULL NULL account_id Account ID contacts accounts account_id task_id Task ID tasks NULL NULL subject Subject tasks NULL NULL owner_id Assigned To contacts contacts contact_id daily_sales Sales transactions accounts account_id sold_on Sold On transactions NULL NULL

तो है सेकंड

  1. पिक स्तंभ कॉलम (वैकल्पिक)
  2. ०१२३५१६४१० को
  3. जोड़ें सूत्र प्रदर्शित करने के लिए
  4. पिक्चर कंडीशन क्लॉज (वैकल्पिक)
  5. "प्रदर्शन परिणाम" बटन चुनें।

ths फॉर्म का पहला भाग display_label कॉलम में सूचीबद्ध सभी मान प्रदर्शित करेगा।

एक उपयोगकर्ता उठाया Name, First Name, Last Name

तो क्वेरी के बाद क्वेरी किया जाता है यह निष्पादित किया जाएगा इस

SELECT accounts.account_name, contacts.first_name, contacts.last_name 
FROM accounts 
INNER JOIN contacts ON contacts.account_id = accounts.account_id 

की तरह देखने की जरूरत होगी।

या, यदि उपयोगकर्ता ने "नाम, बिक्री" चुना है। फिर उपयोगकर्ता कॉलम daily_sales पर एसयूएम फ़ंक्शन लागू करना चाहता है। और अंत में उपयोगकर्ता के लिए Sold On between '2014-01-01 00:00:00' AND '2014-10-01 00:00:00'

एक फिल्टर का चयन किया तो क्वेरी इस

SELECT accounts.account_name, SUM(daily_sales) AS daily_sales 
FROM accounts 
LEFT JOIN sales ON sales.account_id = accounts.account_id 
WHERE sales.sold_on BETWEEN '2014-01-01 00:00:00' AND '2014-10-01 00:00:00' 
GROUP BY accounts.account_name 

तरह देखने के लिए के बाद क्वेरी किया जाता है यह निष्पादित किया जाएगा की आवश्यकता होगी।

मैं ऐसी क्वेरी कैसे उत्पन्न कर सकता हूं? क्या मुझे field_relations तालिका में और कॉलम जोड़ने की आवश्यकता है?

मैं उपयोगकर्ता चश्मा को पकड़ने के लिए PHP फॉर्म बनाने के तरीके से चिंतित नहीं हूं लेकिन मैं यह समझने की कोशिश कर रहा हूं कि वे MySQL क्वेरी को सही तरीके से कैसे उत्पन्न करें?

आपकी सहायता और समय के लिए अग्रिम धन्यवाद।

उत्तर

0

सबसे पहले, शायद आप PHP/MySQL के लिए उपलब्ध कई ओआरएम (ऑब्जेक्ट रिलेशनशिप मैनेजमेंट) सिस्टमों में से किसी एक को बेहतर तरीके से देखेंगे।

लेकिन पहिया को फिर से शुरू करना अपेक्षाकृत आसान है, बशर्ते आप इसे छोटा रखें (जिसका अर्थ है कि आप केवल को बहुत सरल प्रश्न हल कर सकते हैं)।

यदि ऐसा है, तो मान लीजिए कि हमें केवल आंतरिक जुड़ने की आवश्यकता है और वे सभी एक-से-अधिक प्रकार हैं (वास्तव में यह सख्त आवश्यकता नहीं है, जैसा कि हम देखेंगे)। हम एक DIY ORM (मुझे लगता है एक और अधिक उपयुक्त नाम 'DIY Orm Cthulhu Fhtagn' की तरह कुछ हो जाएगा)

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

// This just maps what fields are in what tables 
$tables = array(
    'contacts' => array(
     'first_name' => true /* or an array of information such as SQL type, etc. */ 
    ); 
); 

// This maps all the JOINs 
$orm = array(
    'contacts' => array(
     'accounts' => array(
      'on' => array('account_id', 'account_id'), 
      'type' => 'LEFT JOIN', // 
     ) 
    ) 
); 

तो तुम $ selectFields की सूची के साथ शुरू करते हैं। आप इन क्षेत्रों को $unresolvedFields में कॉपी करते हैं, और एक के बाद एक की जांच शुरू करते हैं। आपका लक्ष्य सभी क्षेत्रों को हल करना है।

छद्म कोड (वास्तव में नहीं तो छद्म):

while (!empty($unresolvedFields)) { 
    $changes = false; 
    // Try to resolve one of them. 
    foreach ($unresolvedFields as $i => $field) { 
     // Try to resolve it. 
     list($tableName, $fieldName) = explode('.', $field); 

     // Did we already select from this table? 
     if (array_key_exists($tableName, $selectedTables)) { 
      // Yes, so this field has been resolved for free. 
      $changes = true; 
      $resolvedFields[] = $field; 
      array_push($selectedTables[$tableName], $fieldName); 
      unset($unresolvedFields[$i]; 
      // On to the next field. 
      continue; 
     } 
     // This is the first time we see this table. 
     // Is this the VERY FIRST table (assume it's the "lead" table -- 
     // it's not necessary but it simplifies the code)? 
     if (empty($selectedTables)) { 
      // Yes. We need do no more. 
      $selectedTables[$tableName] = array($fieldName); 
      $changes = true; //-// 
      $resolvedFields[] = $field; //-// 
      unset($unresolvedFields[$i]; //-// 
      // On to the next field. //--// 
      continue; //--// 
     } // We could also put this check before the last. If we did, the 
     // lines above marked //-// could be left out; those with //--// should. 
     // And we would need $selectedTables[$tableName] = array(/*EMPTY*/); 

     // We did not see this table before, and it's not the first. 
     // So we need a way to join THIS table with SOME of those already used. 

     // Again we suppose there're no ambiguities here. This table HAS a 
     // link to some other. So we just need ask, "WHICH other? And do we have it?" 
     $links = $orm[$tableName]; 

     $useful = array_intersect_keys($orm[$tableName], $selectedTables); 

     // $useful contains an entry 'someTable' => ('on' => ...) 
     // for each table that we can use to reference $tableName. 
     // THERE MUST BE ONLY ONE, or there will be an ambiguity. 
     // Of course most of the time we will find none. 
     // And go on with the next field... 
     if (empty($useful)) { 
      continue; 
     } 
     // TODO: check count($useful) is really 1. 
     $changes = true; 
     $selectedTables[$tableName] = array($fieldName); 
     list($joinWith, $info) = each($useful[0]); 
     // We write SQL directly in here. We actually shouldn't, but it's faster 
     // to do it now instead of saving the necessary info. 
     // $info could actually also contain the JOIN type, additional conditions... 
     $joins[] = "INNER JOIN {$joinWith} ON ({$tableName}.{$info['on'][0]} 
         = {$joinWith}.{$info['on'][1]})"; 
     unset($unresolvedFields[$i]; 
    } 
    // If something changed, we need to repeat, because a later field could have 
    // supplied some table that could have made joinable an earlier field which we 
    // had given up on, before. 
    if (!$changes) { 
     // But if nothing has changed there's no purpose in continuing. 
     // Either we resolved all the fields or we didn't. 
     break; 
    } 
} 
// Now, if there're still unresolved fields after the situation stabilized, 
// we can't make this query. Not enough information. Actually we COULD, but 
// it would spew off a Cartesian product of the groups of unjoined tables - 
// almost surely not what we wanted. So, unresolveds cause an error. 
if (!empty($unresolvedFields)) { 
    throw new \Exception("SOL"); 
} 

// Else we can build the query: the first table leads the SELECT and all the 
// others are joined. 

$query = "SELECT " . implode(', ', $selectedFields) 
     . ' FROM ' . array_shift($selectedTables) . "\n"; 
// Now for each $selectedTables remaining 
foreach ($selectedTables as $table) { 
    $query .= $joins[$table] . "\n"; 

// Now we could add any WHEREs, ORDER BY, LIMIT and so on. 
... 

एक उपयोगकर्ता उठाया तो नाम, प्रथम नाम, अंतिम नाम

तुम भी एक "अनुवाद" के बीच की आवश्यकता होगी मानव-पठनीय "नाम" और "accounts.account_name"।

Name  ... fields = [ accounts.account_name ], tables = [ accounts ], joins = [ ] 
First Name ... fields = [ a.ac_name, co.first ], tables = [ ac, co ], joins = [ co ] 
Last Name ... contacts is already in tables, so fields = [ 3 fields ], rest unchanged 
+0

हाय, सबसे पहले मैं आपको एक महान जानकारी के लिए धन्यवाद देना चाहता हूं। अब, यह मेरी समझ है कि मुझे निम्नलिखित 2 कॉलम 'accounts.account_name',' खाता नाम '(जो मेरे पास field_relation नामक तालिका में है) के साथ एक सरणी प्राप्त करने की आवश्यकता है। लेकिन ऐसी कुछ चीजें हैं जिन्हें मैं समझ नहीं पा रहा हूं आपके कोड में मुझे '$ orm' सरणी कहां मिलती है? मैं INNER या LEFT में शामिल होने का निर्णय कैसे ले सकता हूं? मैं इसे कैसे तैयार करूं? मुझे लगता है कि '$ टेबल' पोस्ट मूल्य '$ _POST ['फ़ील्ड']' होगा; अंत में, आपके पास {$ joinWith} है ...... वह क्या करता है? मैंने कभी भी {} का उपयोग नहीं किया है, इसलिए मुझे नहीं पता कि उनके पीछे क्या विचार है। – Jaylen

+0

मुझे घुंघराले ब्रैकेट का उपयोग करने का बिंदु मिला। मैंने संदर्भ के लिए इस प्रश्न का उपयोग किया http://stackoverflow.com/questions/2596837/curly-braces-in-string-in-php – Jaylen

+0

मैंने आपको क्रेडिट दिया क्योंकि आपने मुझे वह सुराग दिया जो मुझे शुरू करने की आवश्यकता है। – Jaylen

0

एसक्यूएल क्वेरी को बस एक साधारण स्ट्रिंग बिल्डिंग व्यायाम के रूप में बनाने के बारे में सोचें।पिछले पृष्ठ पर प्रपत्र से पोस्ट किए गए मान, जब आप अपनी field_relations तालिका का संदर्भ लेंगे, तो क्वेरी में इच्छित कॉलम और टेबल की पहचान करें।

पहला पोस्ट मूल्य तालिकाओं में से किसी एक फ़ील्ड की पहचान करेगा, आपको बताएगा कि आपको एक खंड से आवश्यकता है। फिर जैसे ही आप दूसरी तालिका से किसी फ़ील्ड से मिलते हैं, जो आपको INNER जॉइन संपर्क (या बिक्री) को contact.account_id = accounts.account_id क्लॉज पर जोड़ने के लिए कहता है। यदि आप बाद में तीसरी तालिका से किसी फ़ील्ड से मिलते हैं, तो आपको एक और जॉइन क्लॉज जोड़ना होगा।

आपको field_relations में संबंधित_to और related_to_field कॉलम की आवश्यकता नहीं है, क्योंकि फ़ील्ड_रेलेशन तालिका में संदर्भित कॉलम नाम फ़ॉर्म से पोस्ट किया गया है, जब आपको फ़ील्ड से कौन सी तालिका आती है।

+0

मुझे यकीन नहीं है कि इनर जॉइन बनाम बाएं जॉइन गतिशील रूप से उपयोग कब किया जाए। साथ ही, जॉइन को कैसे जानना है इस कॉलम संपर्कों पर होना चाहिए .account_id = accounts.account_id उपयोगकर्ता को संबंध नहीं पता होगा। इसलिए वे इस उपकरण को संबंध को समझने देना चाहते हैं। – Jaylen

+0

@ माइक अंदरूनी जुड़ने बनाम बाएं बाहरी शामिल जानकारी उपलब्ध नहीं है। हम उस तालिका के डेटा के आधार पर नहीं जानते हैं। –

+0

@ माइक, यदि आपके पास विदेशी कुंजी परिभाषित हैं, तो आप समझदारी से ऐसी जुड़ी स्थितियों को समझने के लिए info_schema में हमेशा देख सकते हैं। जहां तक ​​बाएं बनाम आईएनएनईआर, आप संदर्भ फ़ील्ड का निरीक्षण कर सकते हैं यह देखने के लिए कि क्या वे शून्य हैं। – Uueerdo

0

आप एक ORM का प्रयोग क्यों नहीं है: एक बार जब आप, हालांकि, एल्गोरिथ्म ऊपर उन रिकॉर्ड मिलेगा? जानने के लिए और लागू करने में आसान: इस मामले में सिद्धांत बहुत उपयोगी है:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html

आप dinamically इकाई और फ़ील्ड जोड़ने और उन्हें एक साथ शामिल हो सकते हैं।

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