簡體   English   中英

使用子查詢在varchar列上進行聯接

[英]JOIN on varchar column with subquery

我知道這不是推薦的join表的方式。 但這僅與一個人的一份很少使用的報告有關,我不想為此更改數據模型。

我有兩個表ModelSparePart ,它們不是通過外鍵直接鏈接的。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM