在两列上连接1个表的最佳方法是什么

时间:2014-12-16 20:14:15

标签: sql-server tsql

我搜索并看过其他类似的问题,但没有任何帮助我。

以下表格的示例:

dbo.Product

PRODUCTID | LEVEL | SOMEFIELD1 | SOMEFIELD2
500         01      Blue         Large
450         102     Black        Large
....
250         03      Orange       Medium

dbo.Level

LEVEL | ProductID
01      500
102     450
104     400 
02      350
101     300
03      250

dbo.LevelMap

LEVEL1 | LEVEL2
01       101
01       102
01       103
02       104
02       105
02       106

我现在的加入非常缓慢,因为我这样做:

SELECT
p1.ProductID
lm1.Level1,
lm1.Level2,
... -- other fields from other tables here
FROM
dbo.Product p1,
INNER JOIN 
dbo.Level l1 ON 
l1.ProductID = p1.ProductID
LEFT JOIN dbo.LevelMap lm1
    ON (l1.Level = lm1.Level1 OR
       l1.Level = lm1.Level2)

我使用OR语句加入dbo.LevelMap lm1两次。我想避免使用UNION,因为实际的SQL代码很大,我发现很难维护两组代码(每个联合一个代码)。

我想要做的就是返回给定Level1的所有Level2Leveldbo.Level表包含Level1和Level2值的混合,因此我需要连接两次到dbo.LevelMap表。以下是传递ProductID值400时理想结果集的样子:

PRODUCTID | LEVEL1 | LEVEL2
400         02       104

在JOIN中,它看到值104,在LEVEL2列上匹配它,然后获得相应的LEVEL1值。

问题是由于联接中的OR,这种情况运行得非常慢。这些表有数千条记录可供匹配。

2 个答案:

答案 0 :(得分:1)

听起来你正在寻找的是:

"查找LevelMap.Level1或LevelMap.Level2"

列中存在104的位置

如果是这种情况,那么您可以执行以下操作:

SELECT *
FROM LevelMap map
WHERE map.Level1 = '104' OR map.Level2 = '104'

如果从LevelMap返回正确的结果,您只需加入Level表一次。

选项#2,加入两次并获取所需内容:

SELECT l1.Column1, l2.Column2
FROM LevelMap map
     INNER JOIN Level l1 ON (map.Level1 = l1.Level)
     INNER JOIN Level l2 ON (map.Level2 = l2.Level)
WHERE map.Level1 = '104' OR map.Level2 = '104'

关于这一点的好处是你正在做两个内连接。

答案 1 :(得分:1)

左边的连接对我来说毫无意义,因为l1甚至没有返回

当一个OR进入循环时,OR通常非常难 首先在这些列上放置索引

我刚看到情况
就像我说左边没有目的(我可以看到)

SELECT
    lm1.Level1,
    lm1.Level2
FROM
    dbo.Level l1
JOIN dbo.LevelMap lm1 
    ON l1.Level = 104  
   AND (    l1.Level = lm1.Level1 
         OR l1.Level = lm1.Level2 ) 

我打赌你用这个来获得更好的表现 所以你必须维护单独的查询

SELECT
     lm1.Level1,
     lm1.Level2
FROM
     dbo.Level l1
JOIN dbo.LevelMap lm1 
  ON l1.Level = 104
 AND l1.Level = lm1.Level1 
UNION 
SELECT
     lm1.Level1,
     lm1.Level2
FROM
     dbo.Level l1
JOIN dbo.LevelMap lm1
  ON l1.Level = 104
 AND l1.Level = lm1.Level2 

这似乎不是3NF
我怀疑您的查询问题是错误数据设计的产物