如何解决连接4个表并分配默认行
我有以下4张桌子:
商店:
id | name
------------------
1 Store 1
2 Store 2
3 Store 3
4 Store 4
5 Store 5
6 Store 6
ITEM_TYPES:
type | description
----------------------
*A *All (Automatically all stores would have this item)
*SP *Store_Specfic (Only a specific store would have this item)
T Toys
H Home
P Pet
STORES_ITEM_TYPES:
STORE_ID | ITEM_TYPE
------------------------
1 T
1 P
3 T
5 T
5 H
5 P
项目:
ITEM_NAME | SPECIFIC_STORE_ID | ITEM_TYPE
--------------------------------------------------------------------
CAT NULL P
BROOM NULL H
LEGO NULL T
BATTERY NULL *A
GIFT CARD NULL *A
PARROT NULL P
STORE2 ONLY ITEM 2 *SP
我想输出每个商店的所有商品:
STORE_NAME | ITEM_NAME | ITEM_TYPE
-------------------------------------------------
STORE1 BATTERY *A
STORE1 GIFT CARD *A
STORE1 LEGO *T
STORE1 CAT *P
STORE1 PARROT *P
STORE2 BATTERY *A
STORE2 GIFT CARD *A
STORE2 STORE2 ONLY ITEM *SP
STORE3 BATTERY *A
STORE3 GIFT CARD *A
STORE3 LEGO *T
STORE4 BATTERY *A
STORE4 GIFT CARD *A
STORE5 BATTERY *A
STORE5 GIFT CARD *A
STORE5 CAT *P
STORE5 PARROT *P
STORE5 BROOM *H
STORE6 BATTERY *A
STORE6 GIFT CARD *A
那是怎么回事?我有一些商店。我有一些东西。这些项目具有类型。例如,LEGO
是具有玩具类型的物品。有些项目具有“特殊”类型。这些前缀为“ *”。 *A
类型代表“全部”。这意味着该商品应在每个单独的商店中。还有一种*SP
类型,表示该商品应仅在一个特定的商店中,并且该商店在ITEMS
表中指明。
我要执行的查询是显示每个商店拥有的所有商品。
我面临的问题是STORES_ITEM_TYPES表未指定特殊类型(* A和* SP)。这是因为假定这些类型已经固有地已经成为所有商店的一部分,所以不需要指定它们(这不是我的数据模型)。
我尝试了以下查询:
SELECT *
FROM stores p,stores_item_types t,items r,item_types y
WHERE stores.store_id = stores_item_types.store_id
AND stores_item_types.item_type = items.item_type
AND stores_item_types.item_type = item_types.item_type
除了特殊项目(* A和* SP)之外,我正在获取所有项目。所以我的输出目前是这样的:
STORE_NAME | ITEM_NAME | ITEM_TYPE
-------------------------------------------------
STORE1 LEGO *T
STORE1 CAT *P
STORE1 PARROT *P
STORE3 LEGO *T
STORE5 CAT *P
STORE5 PARROT *P
STORE5 BROOM *H
这是一个sqlfiddle: sqlfiddle.com/#!9/cae02d/1
解决方法
注意:此答案的先前版本尝试(相当笨拙)解决了异常数据模型的局限性。我认为以下是一种更好,更清晰的方法。
这里的主要问题是数据没有完全标准化,特别是关于商店和商品类型之间的关联。我的建议是使用两个子查询来获得更清晰的stores_item_types
和items
版本,然后制作简单的INNER JOIN
。
让我们从stores_item_types
开始。我们希望派生表明确表示每个商店也都携带*A
类型,并且每个商店还都拥有自己的 *SP
类型。例如:
SELECT *
FROM stores_item_types sit
UNION
SELECT store_id,'*A'
FROM stores
UNION
SELECT store_id,CONCAT('*SP',store_id)
FROM stores
会产生这样的东西:
STORE_ID ITEM_TYPE
1 *A
1 *SP1
1 P
1 T
2 *A
2 *SP2
3 *A
3 *SP3
... ...
,依此类推。我们还需要items
的派生版本,以匹配新类型*SP1
,*SP2
等。
SELECT
item_name,specific_store_id,CONCAT(item_type,IFNULL(specific_store_id,'')) item_type
FROM items
然后,最终查询将如下所示:
SELECT
s.name store_name,i.item_name,i.item_type
FROM stores s
INNER JOIN (
SELECT *
FROM stores_item_types sit
UNION
SELECT store_id,'*A'
FROM stores
UNION
SELECT store_id,store_id)
FROM stores ORDER BY store_id,item_type
) sit ON s.store_id = sit.store_id
INNER JOIN (
SELECT
item_name,'')) item_type
FROM items
) i ON i.item_type = sit.item_type
ORDER BY s.store_id,sit.item_type
您可以在this fiddle中看到此查询的运行情况。
,您能检查一下是否符合您的期望
我已经使用union all来区分3个不同的item_types
第一个联合: :针对那些我们在stores_item_types
中匹配了商品并排除了*A
和*SP
之类的商品的人。 / p>
第二个联合: 仅item_type = '*A'
,并使用所有可用的商店ID进行交叉联接。
第三联盟: 仅item_type='*SP'
,并与商店ID一起加入以包括到特定商店。
select *
from
(
-- for all matched items in store_item_types
select st.id,st.name,it.item_name,it.item_type
from stores st
join stores_item_types sit
on st.id = sit.store_id
and sit.item_type not in ('*A','*SP')
join items it
on sit.item_type = it.item_type
join item_types ity
on sit.item_type = ity.type
union all
-- item type *A for all stores
select st.id,it.item_type
from stores st
cross join items it
on it.item_type = '*A'
union all
-- specific items for specific store
select st.id,it.item_type
from stores st
join items it
on it.specific_store_id = st.id
where it.item_type = '*SP'
) a
order by id,case item_type
when '*A' then 1
when 'H' then 2
when 'P' then 3
when 'T' then 4
when '*SP' then 5
else 6
end;
注意:为方便起见,我下了额外的订单以查看可以删除的输出。而且我只选择了根据预期输出所必需的列,并且可以根据需要添加其他列。
Db<>fiddle供参考
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。