2009-11-06 37 views
9

Cách tốt nhất để xuất dữ liệu từ nhiều bảng trong MySQL là gì. Tôi về cơ bản làm việc với các chi tiết sản phẩm. Giả sử một sản phẩm có 150 thuộc tính của dữ liệu. Làm thế nào tôi có thể xuất nó trong một hàng và sau đó xuất nó sang một tệp phẳng ở định dạng CSV hoặc tabdelimited.Quá nhiều bảng; MySQL chỉ có thể sử dụng 61 bảng trong một tham gia

Nhận lỗi Quá nhiều bảng; MySQL chỉ có thể sử dụng 61 bảng trong một tham gia

/**** Get Resultset *****/ 
$rs = mysql_query($sql); 
/**** End of Get Resultset *****/ 

$objProfileHistory->addHistory($this->profile_id, "Loaded ". mysql_num_rows($rs)." records"); 


$this->runQuery($sql); 

$this->exportToCSV(); 

/** 
    * getAttributeDetails 
    */ 
function getAttributeDetails(){ 
    global $dbObj, $profile; 

    $base_table = "catalog_product_entity"; 
    $select = array(); 
    $tables = array(); 
    $i = 0; 

    $profile->showLog("Start fields mapping", "success"); 

    if(is_array($this->attributes_in_db) && sizeof($this->attributes_in_db) > 0){ 
    $arr = implode("','", $this->attributes_in_db); 
    $sql = "select attribute_id, attribute_code, backend_type, frontend_input 
     from eav_attribute 
     where attribute_code in ('".$arr."') 
     and entity_type_id = 
     (select entity_type_id 
      from eav_entity_type 
      where entity_type_code = 'catalog_product')"; 
    $rs = $dbObj->customqry($sql); 

    if($rs){ 
    while($row = mysql_fetch_assoc($rs)){ 
     $backend_type = $row["backend_type"]; 
     $attribut_code = $row["attribute_code"]; 
     $attribute_id = $row["attribute_id"]; 
     $frontend_input = $row["frontend_input"]; 
     switch($backend_type){ 
     case "text": 
     $where[] = $base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id; 
     $and[] = $base_table.".entity_id=".$base_table."_".$backend_type."".$i.".entity_id"; 
     $select[] = $base_table."_".$backend_type."".$i.".value as ".$attribut_code; 
     $tables[] = $base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i; 
     break; 

     case "decimal": 
     $where[] = $base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id; 
     $and[] = $base_table.".entity_id=".$base_table."_".$backend_type."".$i.".entity_id"; 
     $select[] = $base_table."_".$backend_type."".$i.".value as ".$attribut_code; 
     $tables[] = $base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i; 
     break; 

     case "static": 
     $where[] = $base_table."".$i.".entity_id=".$base_table.".entity_id"; 
     $and[] = $base_table.".entity_id=".$base_table."".$i.".entity_id"; 
     $select[] = $base_table."".$i.".".$attribut_code." as ".$attribut_code; 
     $tables[] = $base_table." as ".$base_table."".$i; 
     break; 

     case "int": 
     if($attribut_code == "tax_class_id" && $frontend_input == "select"){ 
     $where[] = "tax_class{$i}.class_id=(select ".$base_table."_".$backend_type."".$i.".value from ".$base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i." where ".$base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id." and ".$base_table."_".$backend_type."".$i.".entity_id=".$base_table.".entity_id limit 1))"; 
     $and[] = ""; 
     $select[] = "tax_class{$i}.class_name as {$attribut_code}"; 
     $tables[] = "tax_class as tax_class{$i}"; 
     } else if($frontend_input == "select"){ 
     $where[] = "eav_attribute_option_value{$i}.option_id=(select ".$base_table."_".$backend_type."".$i.".value from ".$base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i." where ".$base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id." and ".$base_table."_".$backend_type."".$i.".entity_id=".$base_table.".entity_id limit 1))"; 
     $and[] = ""; 
     $select[] = "eav_attribute_option_value{$i}.value as {$attribut_code}"; 
     $tables[] = "eav_attribute_option_value as eav_attribute_option_value{$i}"; 
     } else { 
     $where[] = $base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id; 
     $and[] = $base_table.".entity_id=".$base_table."_".$backend_type."".$i.".entity_id"; 
     $select[] = $base_table."_".$backend_type."".$i.".value as ".$attribut_code; 
     $tables[] = $base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i; 
     } 
     break; 

     case "varchar": 
     $where[] = $base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id; 
     $and[] = $base_table.".entity_id=".$base_table."_".$backend_type."".$i.".entity_id"; 
     $select[] = $base_table."_".$backend_type."".$i.".value as ".$attribut_code; 
     $tables[] = $base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i; 
     break; 

     case "datetime": 
     $where[] = $base_table."_".$backend_type."".$i.".attribute_id=".$attribute_id; 
     $and[] = $base_table.".entity_id=".$base_table."_".$backend_type."".$i.".entity_id"; 
     $select[] = $base_table."_".$backend_type."".$i.".value as ".$attribut_code; 
     $tables[] = $base_table."_".$backend_type." as ".$base_table."_".$backend_type."".$i; 
     break; 
     }//switch 
     $i++; 
    }//while 


    $sql = "select ".implode(",", $select)." from ".$base_table; 
    for($i=0; $i < sizeof($select); $i++){ 
     $sql .= " left join ". $tables[$i] . " on (".$where[$i];//." and ".$and[$i].")"; 
     if(strlen($and[$i]) > 0){ 
     $sql .= " and ".$and[$i].")"; 
     } 
    }//for 
    $sql .= " group by {$base_table}.entity_id "; 
    }//if 
    //echo $sql; exit; 
    return $sql; 
    } 
    //echo $sql; 
    //echo "<pre>";print_r($tables);print_r($select);print_r($where);print_r($and); 
    }//end function 

    /** 
    * runQuery 
    */ 
    function runQuery($sql){ 
    global $dbObj, $profile; 
    if($sql != ""){ 
    $rs = $dbObj->customqry($sql); 
    $profile->showLog("Loaded ". mysql_num_rows($rs) ." records", "success"); 
    if($rs){ 
    $i = 0; 
    while($row = mysql_fetch_assoc($rs)){ 
     $cnt = sizeof($this->attributes_in_db); 
     for($j=0; $j < $cnt; $j++){ 
     $db_key = $this->attributes_in_db[$j]; 
     $file_key = $this->attributes_in_file[$j]; 
     $this->export_data[$i][$db_key] = $row[$db_key]; 
     } 
     $i++; 
    }//while 
    } 
    }//if 
    }//end function 


    /** 
    * exportToCSV 
    */ 
    function exportToCSV(){ 
    global $smarty, $objProfileHistory, $profile; 
    //$newFileName = $smarty->root_dir."/export/".$this->filename; //file name that you want to create 
    $cnt = sizeof($this->var_array); 
    for($i=0; $i < $cnt; $i++){ 
    extract($this->var_array[$i]); 
    }//for 


    if($delimiter = "\t"){ 
    $delimiter = "\t";//$delimiter; 
    } 

    if(strlen($filename) < 1){ 
    $filename = time().".csv"; 
    } 

// echo "<pre>"; 
// print_r($this->action_array); 
// print_r($this->var_array); 
// print_r($this->map_array); 
// exit; 
    # add amazon headers 
    if($this->action_array[0]['type'] == 'header'){ 
//  $template_type = $this->var_array[0]['template_type']; 
//  $version = $this->var_array[0]['version']; 
//  $status_message = $this->var_array[0]['status_message']; 
    $sStr = "TemplateType=".$template_type."{$delimiter}{$delimiter}Version=".$version."{$delimiter}{$delimiter}{$status_message}"; 
    $sStr .= "� ��\n"; //to seprate every record 
    } 





    $export_path = $path; 
    $x_path = $profile->createDir($export_path); 

    $newFileName = $x_path ."/". $filename; 

    $fpWrite = fopen($newFileName, "w"); // open file as writable 

    # create header 
    $cnt_header = sizeof($this->attributes_in_file); 
    for($i=0; $i < $cnt_header; $i++){ 
    $sStr .= $deli . $this->attributes_in_file[$i]; 
    $deli = $delimiter; 
    }//for 
    $sStr .= "� ��\n"; //to seprate every record 

    # attach data 
    $cnt_row = sizeof($this->export_data); 
    for($i=0; $i < $cnt_row; $i++){ 
    $sStr .= $saperator; 
    $newdeli = ""; 
    for($j=0; $j < $cnt_header; $j++){ 
    $key = $this->attributes_in_db[$j]; 
    $sku = $this->export_data[$i]["sku"]; 
+0

CÁCH TỐT NHẤT ĐỂ XUẤT KHẨU DỮ LIỆU TỪ BẢNG NHIỀU LIỆU TRONG MYSQL. M CƠ BẢN LÀM VIỆC VỚI CHI TIẾT SẢN PHẨM. SAY SẢN PHẨM CÓ 150 thuộc tính của dữ liệu làm cách nào tôi có thể xuất dữ liệu đó trong một hàng và sau đó xuất nó sang tệp phẳng ở định dạng csv hoặc tabdelimited. – user204245

+1

Thời gian để suy nghĩ lại truy vấn này. Tham gia trên hơn 7 bảng là kẻ giết người hiệu suất đối với bất kỳ cơ sở dữ liệu nào. Bạn đã bao giờ chạy truy vấn này ở bất kỳ đâu? – duffymo

Trả lời

20

Bạn đang sử dụng thiết kế EAV và cố gắng xây dựng lại một hàng từ một số thuộc tính khác nhau. Điều này chỉ ra một trong nhiều mìn bạn sẽ gặp phải bằng cách sử dụng thiết kế EAV: có một giới hạn thực tế về số lượng các phép nối mà bạn có thể thực hiện trong một truy vấn SQL đơn.

Đặc biệt trong MySQL - có giới hạn cứng, như bạn đã tìm thấy. Nhưng ngay cả trong các thương hiệu RDBMS khác, có một giới hạn hiệu quả vì chi phí của các phép nối là hình học đối với số lượng các bảng.

Nếu bạn sử dụng EAV, không cố gắng xây dựng lại một hàng trong SQL như thể bạn đã có thiết kế cơ sở dữ liệu thông thường. Thay vào đó, hãy tìm nạp các thuộc tính dưới dạng các hàng, được sắp xếp theo id thực thể. Sau đó xử lý chúng trong mã ứng dụng của bạn. Điều này có nghĩa là bạn không thể đổ dữ liệu trong một bước - bạn phải viết mã để lặp qua các hàng thuộc tính, và cải cách mỗi hàng dữ liệu trước khi bạn có thể xuất nó.

EAV không phải là thiết kế cơ sở dữ liệu tiện lợi. Có rất nhiều nhược điểm đắt tiền khi sử dụng nó, và bạn chỉ cần nhấn một trong số đó.


Xem http://www.simple-talk.com/opinion/opinion-pieces/bad-carma/ để biết câu chuyện tuyệt vời về cách sử dụng EAV phải chịu một doanh nghiệp.

Và cũng xem http://en.wikipedia.org/wiki/Inner-platform_effect vì EAV là ví dụ về mẫu Chống này.


Tôi hiểu cần phải hỗ trợ một tập hợp thuộc tính động cho mỗi sản phẩm trong một danh mục. Nhưng EAV sẽ giết ứng dụng của bạn. Dưới đây là những gì tôi làm để hỗ trợ các thuộc tính động:

  • Xác định cột thực trong bảng cơ sở cho từng thuộc tính chung cho tất cả các loại sản phẩm. Tên sản phẩm, giá, số lượng hàng tồn kho, v.v. Làm việc khó để hình dung sản phẩm sản phẩm kinh điển để bạn có thể bao gồm nhiều thuộc tính nhất có thể trong bộ này.

  • Xác định thêm một cột loại TEXT cho tất cả các thuộc tính bổ sung của từng loại sản phẩm nhất định. Lưu trữ trong cột này là Serialized LOB thuộc tính, theo bất kỳ định dạng nào phù hợp với bạn: XML, JSON, YAML, DSL tự chế của riêng bạn, v.v.

    Hãy coi đây là một cột trong truy vấn SQL của bạn. Bất kỳ tìm kiếm, sắp xếp hoặc hiển thị nào bạn cần thực hiện dựa trên các thuộc tính này đều yêu cầu bạn tìm nạp toàn bộ blob TEXT vào ứng dụng của bạn deserialize nó và phân tích các thuộc tính bằng cách sử dụng mã ứng dụng.

2

Nếu bạn có nhiều thuộc tính này, tôi cho rằng đó là cơ sở dữ liệu thưa thớt, vì vậy bạn có rất nhiều không gian lãng phí.

Bạn có thể muốn xem xét sử dụng cơ sở dữ liệu Giá trị thuộc tính-Giá trị thay thế, nếu có thể.

http://en.wikipedia.org/wiki/Entity-attribute-value_model

Điều này mua bạn là một cách để cấu trúc lại cơ sở dữ liệu, nhưng có nó được mở rộng hơn, và giảm bao nhiêu bảng bạn cần. Bạn sẽ có thể đi xuống đến 4-6 bảng (2-3 bảng thực thể với các thuộc tính của chúng). Sẽ khó hơn một chút khi tạo các truy vấn vì tất cả các truy vấn sẽ là động, nhưng nó sẽ đơn giản hóa việc xuất của bạn và việc bảo trì cơ sở dữ liệu sẽ đơn giản hơn.

Nếu bạn phải sử dụng lược đồ này, bạn có thể tạo nhiều trình kích hoạt và sau đó bạn có thể gọi trình kích hoạt, đang nối nhiều bảng và sau đó thực hiện truy vấn của bạn, nhưng bạn sẽ có hiệu suất rất lớn.

UPDATE:

Từ một bảng EAV đang được sử dụng, và MySQL không làm một chức năng trục bạn có thể muốn đọc những câu trả lời cho câu hỏi này: Làm thế nào để xoay một MySQL thực thể attribute- lược đồ giá trị How to pivot a MySQL entity-attribute-value schema

+0

Anh * đang sử dụng EAV. –

+0

Tôi thấy rằng bây giờ, wow. –

1

Nếu bạn đang sử dụng EAV và bạn muốn xuất một số lượng lớn thuộc tính cùng một lúc, cách tốt nhất là sử dụng nhiều bảng tạm thời.

Mỗi bảng tạm thời sẽ có cùng cột khóa chính. Sau đó, tham gia tất cả chúng và xuất thành csv.

Tôi không biết mình có muốn làm một ví dụ hoàn chỉnh không, nhưng tôi sẽ cố gắng làm một phác thảo hy vọng sẽ làm mọi thứ rõ ràng hơn.

1.) Lấy danh sách thuộc tính bạn muốn xuất. Bạn sẽ sử dụng attribute_ids của họ trong phần nối với bảng thuộc tính EAV của bạn.

2.) Tách các thuộc tính để bạn không vượt quá giới hạn tham gia. Bạn cần bảng gốc và 1 bảng cho mỗi lần tham gia, vì vậy bạn có thể có 60 thuộc tính cho mỗi bảng trong lược đồ này.

3.) Tạo bảng tạm thời "phẳng" cho từng nhóm thuộc tính. Nó sẽ giống như thế này

CREATE TEMPORARY TABLE temp1 
[(create_definition,...)] 
SELECT t1.product_id, t1.sku, t2.color, GROUP_CONCAT(t3.sizes SEPARATOR ',') as sizes, 
... 

#(suppose the product has multiple sizes and you want them shown comma-separated in your export) 

FROM products t1 
LEFT JOIN eav_attribute_values t2 ON t1.product_id = t2.product_id AND t2.attribute_id = 55 
LEFT JOIN eav_attribute_values t3 ON t1.product_id = t2.product_id AND t2.attribute_id = 76 
... etc for up to 60 attributes 

CREATE TEMPORARY TABLE temp2 ... # repeat for next 60 attributes 

4.) Giờ đây, bạn có cùng một khóa chính tạm thời (product_id và/hoặc product_sku). Giả sử bạn có ít hơn 60 bảng tạm thời (điều này sẽ vô lý), bây giờ bạn có thể tham gia tất cả những bảng đó và tạo một bảng duy nhất.

Trong hệ thống của mình, tôi không nghĩ mình đã vượt quá 3 bảng tạm thời và điều đó khá nhiều.

CREATE TEMPORARY TABLE export_data 
[(create_definition,...)] 
SELECT t1.*, t2.*, t3.* FROM # though I would not actually use * here b/c it would cause repeated key fields. I would list out all the columns 
temp1 t1 LEFT JOIN temp2 t2 ON t1.product_id = t2.product_id 
LEFT JOIN temp3 t3 ON t1.product_id = t3.product_id # etc for more joins 

5.) Xuất. Sử dụng tính năng xuất tệp của MySQL để tạo CSV. Gửi nó cho người dùng bằng PHP.

Tôi hy vọng rằng sẽ giúp.

Cũng lưu ý rằng quy trình trên thực hiện khá nhanh chóng đối với tôi. Lý do để sử dụng bảng tạm thời là vì chúng sẽ tự động bị xóa sau khi sử dụng và vì nhiều người dùng có thể chạy cùng một loại quy trình mà không can thiệp lẫn nhau vì bảng tạm thời chỉ tồn tại đối với người dùng đã tạo chúng.

+0

để chia sẻ một số ví dụ về cách thực hiện? –

+0

@TomKim Tôi đã cập nhật câu trả lời của mình với một phác thảo về những gì tôi sẽ làm. Hãy cho tôi biết nếu nó có ý nghĩa hay không. Cũng lưu ý rằng tôi thực sự đang sử dụng ý tưởng này và nó đang làm việc cho tôi. –

Các vấn đề liên quan