[英]JOIN on varchar column with subquery
我知道這不是推薦的join
表的方式。 但這僅與一個人的一份很少使用的報告有關,我不想為此更改數據模型。
我有兩個表Model
和SparePart
,它們不是通過外鍵直接鏈接的。
Model SparePart
idModel idSparePart
ModelName SparePartDescription
Price
在特殊情況下,模型也是備件(交換單元)。 然后,我需要通過其SparePartDescription
列從SparePart
表中獲得該模型的價格。
例如:
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匹配,我只想選擇一個記錄。
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。 文檔在這里 。
首先,可以將連接條件簡化一些,然后可以使用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內聯函數適用通常更高性能的是相關子查詢,所以我無法預測哪個更快。
嘗試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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.