我知道这不是join
表的推荐方式。但它只与一个人很少使用的报告相关,我不想改变我的数据模型。
我有两个表Model
和SparePart
,它们没有通过外键直接相互链接。
Model SparePart
idModel idSparePart
ModelName SparePartDescription
Price
在特殊情况下,模型也是备件(交换单元)。然后我需要从SparePart
表格通过其SparePartDescription
列获得此模型的价格。
例如:
ModelName = C510
SparePartDescription = C510/Exchange Unit/Exch unit/Red
所以我尝试加入两个表来获得跟随SQL的价格:
SELECT m.idModel, m.ModelName, sp.Price, sp.SparePartDescription
FROM modModel AS m INNER JOIN
tabSparePart AS sp ON m.ModelName =
(SELECT TOP 1 LEFT(sp.SparePartDescription, CHARINDEX('/', sp.SparePartDescription) - 1)order by price desc)
WHERE (CHARINDEX('/', sp.SparePartDescription) > 0)
AND (sp.fiSparePartCategory = 6)
ORDER BY m.ModelName, sp.SparePartDescription
但我得到一个模型的多个记录:
idModel ModelName Price SparePartDescription
569 C510 70,75 C510/Exchange Unit/Exch unit/Red
569 C510 70,75 C510/Exchange Unit/Latin/Generic/Black
569 C510 70,75 C510/Exchange Unit/Latin/Generic/Silver
433 C702 80,72 C702/Exchange Unit/Latin/Generic/Black
433 C702 NULL C702/Exchange Unit/Latin/Generic/Cyan
433 C702 80,72 C702/Exchange Unit/Orange Global/Black
如果有多个备件与SparePartDescription匹配,我只想选择一条记录。
答案 0 :(得分:2)
Sql Server 2005并且更好地引入了'APPLY'运算符,它允许你加入子查询...试试这个。
SELECT m.idModel, m.ModelName, sp.Price, sp.SparePartDescription
FROM modModel AS m
CROSS APPLY
(
SELECT TOP 1 * FROM tabSparePart
WHERE m.ModelName =
LEFT(SparePartDescription, LEN(ModelName))
ORDER BY Price DESC
) sp
WHERE (sp.fiSparePartCategory = 6)
ORDER BY m.ModelName, sp.SparePartDescription
它将'modModel'表连接到子查询'只有最匹配的tabSparePart'。
您还可以使用OUTER APPLY来模拟子查询上的LEFT JOIN。文档为here。
答案 1 :(得分:1)
首先,您的连接条件可以简化一些,然后您可以使用ROW_NUMBER()为结果指定某种顺序,从而允许选择第一个结果(每个模型)。如果没有匹配,我也将其更改为LEFT JOIN。如果不需要,可以很容易地改回INNER JOIN:)
WITH
ranked_results AS
(
SELECT
m.idModel, m.ModelName, sp.Price, sp.SparePartDescription,
ROW_NUMBER() OVER (PARTITION BY m.idModel ORDER BY sp.Price DESC) AS rank
FROM
modModel AS m
LEFT JOIN
tabSparePart AS sp
ON LEFT(sp.SparePartDescription, LEN(m.ModelName)) = m.ModelName
AND (CHARINDEX('/', sp.SparePartDescription) > 0)
AND (sp.fiSparePartCategory = 6)
)
SELECT
*
FROM
ranked_results
WHERE
rank = 1
ORDER BY
ModelName,
SparePartDescription
@ MattMurrell的答案就在我打字的时候出现了。这里的一个区别是选择标准应用于整个集合,而不是在CROSS APPLY中单独应用。 可能具有性能优势,您必须尝试查看。使用内联函数的交叉应用通常与子查询相关的性能更高,因此我无法预测哪个更快。
答案 2 :(得分:1)
尝试使用ROW_NUMBER函数。它保证您只能获得PARTITION BY子句中定义的每个项目之一。
SELECT a.idModel, a.ModelName, Price, SparePartDescription
FROM modModel a
LEFT JOIN
(
SELECT m.idModel, m.ModelName, sp.Price, sp.SparePartDescription
, ROW_NUMBER() OVER (PARTITION BY m.idModel, m.ModelName ORDER BY sp.price DESC) AS r
FROM modModel AS m
INNER JOIN tabSparePart AS sp
ON m.ModelName = LEFT(sp.SparePartDescription, CHARINDEX('/', sp.SparePartDescription) - 1)
WHERE (CHARINDEX('/', sp.SparePartDescription) > 0)
AND (sp.fiSparePartCategory = 6)
) b
ON a.idModel = b.idModel
AND b.r = 1
ORDER BY ModelName, SparePartDescription