从MySQL中的多个表导出数据的最佳方法是什么。我基本上是在处理产品详细信息。假设一个产品具有150个数据属性。如何将其导出为一行,然后将其导出为CSV或制表符分隔格式的平面文件。
错误越来越多 MySQL在一个联接中只能使用61个表
/**** 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"];
您正在使用EAV设计,并尝试根据可变数量的属性来重构单行。这指出了使用EAV设计将遇到的众多地雷之一:在单个SQL查询中可以执行的连接数量有实际限制。
正如您所发现的,尤其是在MySQL中-有一个硬限制。但是,即使在其他RDBMS品牌中,也存在有效的限制,因为联接的成本相对于表的数量是几何的。
如果您使用EAV, 请不要 像在常规数据库设计中 那样尝试在SQL中重新构造行 。取而代之的是,将属性按行获取,并按实体ID排序。然后在您的应用程序代码中对它们进行后处理。这确实意味着您不能一步一步地转储数据- 您必须编写代码以遍历属性行,并在输出数据之前对每一行数据进行重新格式化。
EAV不是方便的数据库设计。使用它有许多昂贵的缺点,而您已经遇到了其中之一。
有关使用EAV如何注定一个企业的伟大故事,请参见http://www.simple-talk.com/opinion/opinion- pieces/bad-carma/。
另外,请参阅http://en.wikipedia.org/wiki/Inner- platform_effect,因为EAV是此反模式的一个示例。
我了解需要支持目录中每个产品的动态属性集。但是,EAV会杀死您的应用程序。这是我支持动态属性的操作:
在基本表中为所有产品类型共有的每个属性定义一个实列。产品名称,价格,库存数量等。努力想象规范的 产品 实体,以便您可以在此集中包含尽可能多的属性。
TEXT为每种给定产品类型的所有其他属性定义一个类型列。以适合您的格式存储在此列中,作为属性的序列化LOB:XML,JSON,YAML,您自己的自制DSL等。
TEXT
将此视为SQL查询中的单个列。根据这些属性进行的任何搜索,排序或显示操作,都需要将整个TEXTBlob 提取到应用程序中,以对它进行反序列化,然后使用应用程序代码分析属性。