【问题标题】:Joining three tables and trying to get null values连接三个表并尝试获取空值
【发布时间】:2011-02-10 11:22:49
【问题描述】:

我有三个表:tblProduct、lkpFoodgroup、tblCustomer。还有一个联结表:jctCustomerFoodgroup

列是这样的:

**tblProduct**
+---+----------------+
|PK |int_ProductID   |
|FK |int_FoodgroupID |
|   |str_ProductName |
+---+----------------+

**lkpFoodgroup**
+---+-------------------+
|PK |int_FoodgroupID    |
|   |str_FoodgroupHandle|
+---+-------------------+

**tblCustomer**
+---+----------------+
|PK |int_CustomerID  |
|   |str_CustomerName|
+---+----------------+

**jctCustomerFoodgroup**
+---+----------------+
|PK |int_CustomerID  |
|PK |int_FoodgroupID |
|   |int_ProductID   |
+---+----------------+

这些表中最简单的是查找:

**lkpFoodgroup**
+---------------+-------------------+
|int_FoodgroupID|str_FoodgroupHandle|
+---------------+-------------------+
|1              |fruit              |
|2              |meat               |
|3              |bread              |
|4              |cheese             |
+---------------+-------------------+

接下来是客户:

**tblCustomer**
+----------------+-------------------+
|int_CustomerID  |str_CustomerName   |
+----------------+-------------------+
|1               |Bob                |
|2               |Sally              |
|3               |Jane               |
|4               |Billy              |
+----------------+-------------------+

tblProduct 上可以有许多具有相同 Foodgroup 的产品。也可能有一些产品 Foodgroups 中没有产品:

**tblProduct**
+---------------+-----------------+----------------+
|int_ProductID  |int_FoodgroupID  |str_ProductName |
+---------------+-----------------+----------------+
|1              |1                |apple           |
|2              |1                |banana          |
|3              |1                |orange          |
|4              |1                |pear            |
|5              |2                |chicken         |
|6              |2                |beef            |
|7              |2                |fish            |
|8              |2                |turkey          |
|9              |3                |white           |
|10             |3                |wheat           |
+---------------+-----------------+----------------+

联结表上的 PK 是 int_CustomerID 和 int_FoodgroupID 的组合 - 这意味着任何客户只能为每个 Foodgroup 选择一个产品:

**jctCustomerFoodgroup**
+---------------+-----------------+--------------+------------------------+
|int_CustomerID |int_FoodgroupID  |int_ProductID |  --meaning             |
+---------------+-----------------+--------------+------------------------|
|1              | 1               |1             | --Bob, fruit, apple    |
|1              | 2               |6             | --Bob, meat, beef      |
|1              | 3               |9             | --Bob, bread, white    |
|2              | 1               |3             | --Sally, fruit, orange |
|2              | 2               |5             | --Sally, meat, chicken |
|3              | 1               |3             | --Jane, fruit, orange  |
|3              | 3               |9             | --Jane, bread, white   |
|3              | 2               |6             | --Jane, meat, beef     |
+---------------+-----------------+--------------+------------------------+

我正在寻找一个查询,它会给我这样的结果:

**spGetCustomerProductSelections(1) --Get Bob's choices**
+----------------+---------------+-------------------+-------------+---------------+
|int_CustomerID  |int_FoodgroupID|str_FoodgroupHandle|int_ProductID|str_ProductName|
+----------------+---------------+-------------------+-------------+---------------+
|1               |1              |fruit              |1            |apple          |
|1               |2              |meat               |6            |beef           |
|1               |3              |bread              |9            |white          |
|1               |4              |cheese             |null         |null           |
+----------------+---------------+-------------------+-------------+---------------+

**spGetCustomerProductSelections(2) --Get Sally's choices**
+----------------+---------------+-------------------+-------------+---------------+
|int_CustomerID  |int_FoodgroupID|str_FoodgroupHandle|int_ProductID|str_ProductName|
+----------------+---------------+-------------------+-------------+---------------+
|2               |1              |fruit              |3            |orange         |
|2               |2              |meat               |5            |chicken        |
|2               |3              |bread              |null         |null           |
|2               |4              |cheese             |null         |null           |
+----------------+---------------+-------------------+-------------+---------------+

**spGetCustomerProductSelections(4) --Get Billy's choices**
+----------------+---------------+-------------------+-------------+---------------+
|int_CustomerID  |int_FoodgroupID|str_FoodgroupHandle|int_ProductID|str_ProductName|
+----------------+---------------+-------------------+-------------+---------------+
|4               |1              |fruit              |null         |null           |
|4               |2              |meat               |null         |null           |
|4               |3              |bread              |null         |null           |
|4               |4              |cheese             |null         |null           |
+----------------+---------------+-------------------+-------------+---------------+

有什么帮助吗?

【问题讨论】:

  • 如果您生成创建和插入语句而不仅仅是数据,您将获得更大的吸引力。
  • 由于 ProductID 是产品的主键,连接表 CustomerFoodGroup 应该是只有 ProductID 的 CustomerProduct,除非您的业务规则允许您针对不同的食品组购买产品。

标签: sql sql-server tsql


【解决方案1】:

请不要以“sp”开头命名您的程序。它将开始在主数据库中搜索,然后才返回您的数据库。

架构和数据的 DDL

create table lkpFoodgroup
(int_FoodgroupID int, str_FoodgroupHandle varchar(max))
insert lkpFoodgroup values
(1,'fruit'),
(2,'meat'),
(3,'bread'),
(4,'cheese');

create table tblCustomer
(int_CustomerID int, str_CustomerName varchar(max))
insert tblCustomer values
(1,'Bob'),
(2,'Sally'),
(3,'Jane'),
(4,'Billy');

create table tblProduct
(int_ProductID int, int_FoodgroupID int, str_ProductName varchar(max))
insert tblProduct values
(1,'1','apple'),
(2,'1','banana'),
(3,'1','orange'),
(4,'1','pear'),
(5,'2','chicken'),
(6,'2','beef'),
(7,'2','fish'),
(8,'2','turkey'),
(9,'3','white'),
(10,'3','wheat');

create table jctCustomerFoodgroup
(int_CustomerID int, int_FoodgroupID int, int_ProductID varchar(max))
insert jctCustomerFoodgroup values
(1,'1','1'),
(1,'2','6'),
(1,'3','9'),
(2,'1','3'),
(2,'2','5'),
(3,'1','3'),
(3,'3','9'),
(3,'2','6');

存储过程代码

create proc uspGetCustomerProductSelections @customerID int as
select c.int_CustomerID, l.int_FoodgroupID, l.str_FoodgroupHandle, j.int_ProductID, p.str_ProductName
from tblCustomer c
cross join lkpFoodgroup l
left join jctCustomerFoodgroup j on j.int_CustomerID = c.int_CustomerID and j.int_FoodgroupID = l.int_FoodgroupID
left join tblProduct p on p.int_ProductID = j.int_ProductID
where c.int_CustomerID = @customerID

示例执行

exec uspGetCustomerProductSelections 1

输出

int_CustomerID int_FoodgroupID str_FoodgroupHandle  int_ProductID  str_ProductName
-------------- --------------- ---------------------------------------------------
1              1               fruit                1              apple
1              2               meat                 6              beef
1              3               bread                9              white
1              4               cheese               NULL           NULL

【讨论】:

  • 是的,我认为规则是我不能将它们命名为 sp_ - 我认为 sp 很好。
  • 非常感谢cyberkiwi的回答。
  • 也不需要匈牙利符号。你不需要仅仅因为它是一个表就用tbl 前缀命名一些东西;使用有意义的名称。
  • 它在技术和功能上毫无用处,但 WRT 代码读写能力和可读性是有目的的。它也是我们开发标准的一部分。
  • 当您使用匈牙利表示法来表示不是“只是”表的表时,它确实起到了作用,例如连接和查找。
【解决方案2】:

您应该使用外连接(左、右或全)。这些连接将包含空值。

【讨论】:

    猜你喜欢
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2019-08-09
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多