我的系统中有以下(例如简化的)表:
目的是可以为给定类别指定功能,然后在子类别或产品级别覆盖。
有不同类型的要素具有不同的属性,这些类型由与要素具有 1:1 关系的“扩展”表表示。
例如,假设:
- 所有电脑和灯都有交流适配器(类别)
- 所有计算机都有 CPU(类别)
- 所有笔记本电脑和平板电脑都有电池(子类别)
- 所有 MacBook Pro 都有 HDMI 端口(产品)
- 所有 MacBook Pro 和 iPad 都有 Retina 显示屏(产品)
这将被建模为:
分类:
- 特征容器:ID:1
- 类别:id:1,名称:“计算机”
- 特征容器:ID:2
- 类别:id:2,名称:“光”
子类别:
- 特征容器:ID:3
- 子类别:id:3,category_id:1,名称:“桌面”
- 特征容器:ID:4
- 子类别:id:4,category_id:1,名称:“笔记本电脑”
- 特征容器:ID:5
子类别:id:5,category_id:1,名称:“平板电脑”
特征容器:ID:6
- 子类别:id:6 category_id:2,名称:“地灯”
- 特征容器:ID:7
- 子类别:id:7,category_id:2,名称:“台灯”
产品:
- 特征容器:ID:7
- 产品:id:7,subcategory_id:4,名称:“Apple MacBook Air”
- 特征容器:ID:8
- 产品:id:8,subcategory_id:4,名称:“Apple MacBook Pro”
- 特征容器:ID:9
- 产品:id:9,subcategory_id:5,名称:“Apple iPad”
应用于类别的功能:
- 特征:id:1,feature_container_id:1
has_ac_adapter_feature:id:1,model_number:“ABC”
特征:id:2,feature_container_id:2
has_ac_adapter_feature:id:2,model_number:“DEF”
特征:id:3,feature_container_id:1
- has_cpu_feature:id:3,model_number:“123”
应用于子类别的功能:
- 特征:id:4,feature_container_id:4
- has_battery_feature:id:4,battery_type:“锂离子”
- 特征:id:5,feature_container_id:5
- has_battery_feature:id:5,battery_type:“锂离子”
应用于产品的特点:
- 特征:id:6,feature_container_id:8
- has_retina_display_feature: id:6
- 特征:id:7,feature_container_id:9
- has_retina_display_feature: id:7
- 特征:id:8,feature_container_id:8
- has_hdmi_port_feature: id:8
我不会费心为 Light 层次结构插入数据,但你明白了。请记住,我有:
- 数以百万计的产品
- 数以千计的子类别
- 上百个类别
- 几千个特征,主要定义在子类别上,但也有一些定义在产品和类别上。
- 没有什么可说的,通常在类别级别(交流适配器)定义的功能实际上可能只在产品级别定义。这是一个业务呼叫,由灵活性与可维护性驱动。换句话说,我必须假设可以在任何级别分配任何功能。
我想查询以下内容:
给我所有具有 CPU 和 AC 适配器并具有(Retina 显示器或 HDMI 端口)的产品
我应该得到:
- 苹果 MacBook Pro
- 苹果iPad
这是我尝试过的...
我从这样的事情开始:
http://sqlfiddle.com/#!4/2f6cd/4/0
这试图处理继承问题,但后来我很快意识到,如果我开始过滤这个(产品有这个特性和那个特性),我不能轻易找到哪些产品有多个和/或特性(或者我可以?)。
然后我开始做这样的事情:
SELECT prd.id AS prd_id,
CASE
WHEN prd_lvl.ac_ftr = 1
OR cat_lvl.ac_ftr = 1
OR scat_lvl.ac_ftr = 1
THEN
1
ELSE
0
END
AS ac_ftr
FROM product prd
LEFT JOIN (SELECT prd.id AS prd_id,
prd.name AS prd_name,
NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
FROM feature_container fc
INNER JOIN product prd
ON fc.id = prd.id
INNER JOIN feature ftr
ON fc.id = ftr.feature_container_id
LEFT JOIN has_ac_adapter_feature ac_ftr
ON ftr.id = ac_ftr.id
LEFT JOIN has_cpu_feature cpu_ftr
ON ftr.id = cpu_ftr.id
LEFT JOIN has_battery_feature bat_ftr
ON ftr.id = bat_ftr.id
LEFT JOIN has_hdmi_port_feature hdmi_ftr
ON ftr.id = hdmi_ftr.id
LEFT JOIN has_retina_display_feature ret_ftr
ON ftr.id = ret_ftr.id) prd_lvl
ON prd.id = prd_lvl.prd_id
LEFT JOIN ( --All Products and subcategory-level-features assigned
SELECT prd.id AS prd_id,
prd.name AS prd_name,
NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
FROM feature_container fc
INNER JOIN subcategory scat
ON fc.id = scat.id
INNER JOIN feature ftr
ON fc.id = ftr.feature_container_id
INNER JOIN product prd
ON scat.id = prd.subcategory_id
LEFT JOIN has_ac_adapter_feature ac_ftr
ON ftr.id = ac_ftr.id
LEFT JOIN has_cpu_feature cpu_ftr
ON ftr.id = cpu_ftr.id
LEFT JOIN has_battery_feature bat_ftr
ON ftr.id = bat_ftr.id
LEFT JOIN has_hdmi_port_feature hdmi_ftr
ON ftr.id = hdmi_ftr.id
LEFT JOIN has_retina_display_feature ret_ftr
ON ftr.id = ret_ftr.id) scat_lvl
ON prd.id = scat_lvl.prd_id
LEFT JOIN ( --All Products and category-level-features assigned
SELECT prd.id AS prd_id,
prd.name AS prd_name,
NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
FROM feature_container fc
INNER JOIN category cat
ON fc.id = cat.id
INNER JOIN feature ftr
ON fc.id = ftr.feature_container_id
INNER JOIN subcategory scat
ON cat.id = scat.category_id
INNER JOIN product prd
ON scat.id = prd.subcategory_id
LEFT JOIN has_ac_adapter_feature ac_ftr
ON ftr.id = ac_ftr.id
LEFT JOIN has_cpu_feature cpu_ftr
ON ftr.id = cpu_ftr.id
LEFT JOIN has_battery_feature bat_ftr
ON ftr.id = bat_ftr.id
LEFT JOIN has_hdmi_port_feature hdmi_ftr
ON ftr.id = hdmi_ftr.id
LEFT JOIN has_retina_display_feature ret_ftr
ON ftr.id = ret_ftr.id) cat_lvl
ON prd.id = cat_lvl.prd_id order by prd_id
但这有同样的问题:我不能在同一行得到东西。关于如何解决这个问题的任何建议?
谢谢!