加入 4 个表并分配默认行

Joining 4 tables and assigning default rows

我有以下 4 个 table:

商店:

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 table.

中指示

我要查询的是显示每家商店的所有商品。

我面临的问题是 STORES_ITEM_TYPES table 没有指定特殊类型(*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_typesitems,然后做简单的INNER JOINs.

让我们从stores_item_types开始。我们希望派生的 table 明确说明每个商店也带有 *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, CONCAT('*SP', store_id)
  FROM stores ORDER BY store_id, item_type
) sit ON s.store_id = sit.store_id
INNER JOIN (
  SELECT
    item_name,
    specific_store_id,
    CONCAT(item_type, IFNULL(specific_store_id, '')) 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.

第二个联合: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,st.name,it.item_name,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,st.name,it.item_name,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供参考