use*_*245 11 mysql join entity-attribute-value
从MySQL中的多个表导出数据的最佳方法是什么?我基本上都在处理产品细节.假设产品有150个数据属性.如何将其导出到一行,然后将其导出为CSV或tabdelimited格式的平面文件.
获取错误表太多; 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"];
Run Code Online (Sandbox Code Playgroud)
Bil*_*win 22
您正在使用EAV设计,并尝试从可变数量的属性重新构造单行.这指出了使用EAV设计会遇到的众多地雷中的一个:在单个SQL查询中可以执行的连接数量存在实际限制.
特别是在MySQL中 - 正如你所发现的那样,存在一个硬限制.但即使在其他RDBMS品牌中,也存在一个有效的限制,因为连接的成本相对于表的数量是几何的.
如果使用EAV,请不要尝试在SQL中重新构造一行,就像使用传统的数据库设计一样.相反,将属性作为行获取,按实体ID排序.然后在应用程序代码中对它们进行后处理.这意味着您无法在一个步骤中转储数据 - 您必须编写代码以循环遍历属性行,并在输出之前重新构造每一行数据.
EAV不是一种方便的数据库设计.使用它有许多昂贵的缺点,你刚刚打了其中一个.
请参阅http://www.simple-talk.com/opinion/opinion-pieces/bad-carma/,了解有关如何使用EAV注定一项业务的精彩故事.
另请参阅http://en.wikipedia.org/wiki/Inner-platform_effect,因为EAV是此反模式的一个示例.
我理解需要在目录中支持每个产品的动态属性集.但是EAV会杀死你的应用程序.这是我为支持动态属性所做的工作:
在基表中为所有产品类型共有的每个属性定义一个实际列.产品名称,价格,库存数量等.努力想象规范产品实体,以便您可以在此集合中包含尽可能多的属性.
TEXT为每种给定产品类型的所有其他属性定义另一个类型列.存储在此列中作为属性的序列化LOB,以适合您的任何格式存储:XML,JSON,YAML,您自己的自制DSL等.
将其视为SQL查询中的单个列.根据这些属性进行的任何搜索,排序或显示都需要您将整个TEXTblob 提取到应用程序中进行反序列化,并使用应用程序代码分析属性.
| 归档时间: |
|
| 查看次数: |
17243 次 |
| 最近记录: |