来自多个表的UNION或JOIN for SELECT

时间:2014-11-14 14:40:51

标签: sql sql-server join union

我的问题

我试图根据参数从多个表中选择一行,但我对SQL加入的有限知识阻碍了我。有人可能会指出我正确的方向吗?

考虑这些表结构:

+-----------------------+     +---------------------+
| Customers             |     | Sellers             |
+-------------+---------+     +-----------+---------+
| Customer_ID | Warning |     | Seller_ID | Warning |
+-------------+---------+     +-----------+---------+
| 00001       | Test 1  |     | 00008     | Testing |
| 00002       | Test 2  |     | 00010     | Testing |
+-------------+---------+     +-----------+---------+

我想要做的是只有一个SELECT来检索一行,并且在这一行中,它将是基于X_ID字段的每个表的“警告”字段。

期望的结果

因此,如果我提交了以下信息,我会收到以下结果:

示例1:

Customer_ID = 00001
Seller_ID = 00008

Results:
+-----------------------------------+
| Customer_Warning | Seller_Warning |
+------------------+----------------+
| Test 1           | Testing        |
+------------------+----------------+

示例2:

Customer_ID = 00001
Seller_ID = 00200

Results:
+-----------------------------------+
| Customer_Warning | Seller_Warning |
+------------------+----------------+
| Test 1           | NULL           |
+------------------+----------------+

我尝试过什么

这是我当前的代码(我收到了很多行):

SELECT c.Warning 'Customer_Warning', s.Warning AS 'Seller_Warning'
FROM Customers c,Sellers s
WHERE c.Customer_ID = @Customer_ID
    OR s.Seller_ID = @Seller_ID

但我也玩过UNIONUNION ALLJOIN。我应该选择哪种方法?

4 个答案:

答案 0 :(得分:11)

由于您并未真正将表格连接在一起,只需从每个表格中选择一行,您就可以这样做:

SELECT 
    (SELECT Warning 
     FROM Customers 
     WHERE Customer_ID = @Customer_ID) AS Customer_Warning,
    (SELECT Warning 
     FROM Sellers 
     WHERE Seller_ID = @Seller_ID) AS Seller_Warning

答案 1 :(得分:5)

问题是您在每个表格中获得行的笛卡尔积,其中 列具有您正在寻找的值。

我认为您只想AND而不是OR

SELECT c.Warning 'Customer_Warning', s.Warning AS 'Seller_Warning'
FROM Customers c 
JOIN Sellers s
ON c.Customer_ID = @Customer_ID
    AND s.Seller_ID = @Seller_ID

如果性能不够好,您可以加入两个过滤的子查询:

SELECT c.Warning 'Customer_Warning', s.Warning AS 'Seller_Warning'
FROM (SELECT Warnning FROM Customers WHERE c.Customer_ID = @Customer_ID) c,
     (SELECT Warning FROM Sellers s WHERE s.Seller_ID = @Seller_ID) s

但我怀疑SQL能够很好地优化过滤连接。

  

如果其中一个ID不存在,它将不会返回一行。

然后你需要一个FULL OUTER JOIN

SELECT c.Warning 'Customer_Warning', s.Warning AS 'Seller_Warning'
FROM Customers c 
FULL OUTER JOIN Sellers s
ON c.Customer_ID = @Customer_ID
    AND s.Seller_ID = @Seller_ID

答案 2 :(得分:2)

您遇到的问题是,当其中一个表没有行时,您将不会输出任何行。

我建议使用full outer join

解决此问题
SELECT c.Warning as Customer_Warning, s.Warning AS Seller_Warning
FROM Customers c FULL OUTER JOIN
     Sellers s
     ON c.Customer_ID = @Customer_ID AND s.Seller_ID = @Seller_ID;

另外,我强烈建议您不要使用单引号作为列别名。使用单引号表示字符串和日期常量。将它们用于列名可能会导致混淆。在这种情况下,您根本不需要对名称进行分隔。

答案 3 :(得分:0)

到目前为止,我所看到的是您的方案的工作示例。但是,将不相关的数据放在一行背后并没有真正的意义。我建议使用UNION并将代码中的值分开:

SELECT 'C' AS Type, c.Warning
FROM Customers c
WHERE c.Customer_ID = @Customer_ID
UNION
SELECT 'S' AS Type, s.Warning
FROM Sellers s
WHERE s.Seller_ID = @Seller_ID

您可以使用该标志来区分代码中的警告。这将比加入或子查询更有效,并且稍后将很容易理解(重构时)。我知道这不是你在问题中要求的100%,而是我挑战这个问题的原因:)