Sql 连接三个表并尝试获取空值

Sql 连接三个表并尝试获取空值,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有三张表:tblProduct、LKPoodGroup、tblCustomer。和一个连接表:jctCustomerFoodgroup 这些列如下所示: **tblProduct** +---+----------------+ |PK |int_ProductID | |FK |int_FoodgroupID | | |str_ProductName | +---+----------------+ **lkpFoodgroup** +---+-------------------

我有三张表:tblProduct、LKPoodGroup、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              |
+----------------+-------------------+
TBLPProduct上可能有许多产品具有相同的Foodgroup。此外,也可能存在一些没有产品的产品食物组:

**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           |
+---------------+-----------------+----------------+
连接表上的主键是int_CustomerID和int_FoodgroupID的组合-这意味着任何客户只能为每个foodgroups选择一种产品:

**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           |
+----------------+---------------+-------------------+-------------+---------------+

有什么帮助吗?

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

请不要将您的过程命名为以“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

如果您生成的是create和insert语句,而不仅仅是数据,您将获得更大的吸引力。?因为ProductID是product的主键,连接表CustomerFoodGroup应该是CustomerProduct,只有ProductID,除非您有允许您针对不同的食品组购买产品的业务规则。是的,我认为规则是我不能命名它们sp_u-我认为sp很好。非常感谢您的回答cyberkiwi。也不需要匈牙利符号。你不需要仅仅因为它是一个表就用
tbl
前缀来命名它;使用有意义的名称。它在技术上和功能上都是无用的,但是WRT代码的可读性和可读性是有目的的。它也是我们开发标准的一部分。当您使用匈牙利符号来表示并非“仅”表的表时,匈牙利符号确实起到了一定的作用,例如连接和查找。