2016-09-13 121 views
0

我有我使用的多行數據擠入一個變量,像這樣一個存儲過程:替代CROSS APPLY

DECLARE @Description VARCHAR(200); 

SELECT @Description = COALESCE(@Description) + ', ', '') + [Description] 
FROM dbo.DrugDescriptionAndImprints 
WHERE NDC = @NDC; 

我的問題是,我最近有需要做到這一點多的NDC同時生成報告數據。

我目前的解決方案是使用具有表值函數的CROSS APPLY,但由於性能影響,這不是最優的。我希望能夠在視圖或其他東西中「平整」這些數據,但無法在視圖中使用變量。有沒有辦法做到這一點,而不使用CROSS APPLY和表值函數?

下面是引用表值函數:

CREATE FUNCTION [dbo].[fnFlatDescriptionByNdc] 
(
    @NDC VARCHAR(11) 
) 
RETURNS 
@ret TABLE 
(
    [Description] VARCHAR(200) 
) 
AS 
BEGIN 
    DECLARE @Description VARCHAR(200) 
    DECLARE @Imprint1 VARCHAR(40) 
    DECLARE @Imprint2 VARCHAR(40) 

    SELECT @Description = Coalesce(@Description + ', ', '') + [Description] 
    FROM dbo.DrugDescriptionAndImprints WHERE NDC = @NDC 

    SELECT @Imprint1 = COALESCE(Imprint1, '') 
    FROM dbo.DrugDescriptionAndImprints WHERE NDC = @NDC 
    ORDER BY Imprint1 DESC 

    SELECT @Imprint2 = COALESCE(Imprint2, '') 
    FROM dbo.DrugDescriptionAndImprints WHERE NDC = @NDC 
    ORDER BY Imprint2 DESC 

    INSERT INTO @ret ([Description]) 
    SELECT @Description + CASE WHEN @Imprint1 <> '' OR @Imprint2 <> '' THEN ' (' + 
     CASE WHEN @Imprint1 <> '' THEN @Imprint1 + 
      CASE WHEN @Imprint2 <> '' THEN '/' + @Imprint2 
      ELSE '' 
      END 
     ELSE @Imprint2 END + ')' ELSE '' END 

    RETURN 
END 

我與SQL Server 2008 R2的工作。

編輯 下面是一些示例數據顯示什麼我一起工作:

NDC    ProdDescAbbr   Description  Imprint1  Imprint2 
00005250033  FIBERCON TAB 625MG film-coated  LL   F 1 
00005250033  FIBERCON TAB 625MG tan    LL   F 1 
00005250033  FIBERCON TAB 625MG scored    LL   F 1 
00005250033  FIBERCON TAB 625MG oblong    LL   F 1 

回答

1

你什麼你現在正在做你想做的事是有點混亂,但我會解釋解決我所看到的問題。

我想你是說你不想使用用戶定義的函數,這是很好的。 UDF沒有性能上的提升,事實上,如果您使用除了內聯表函數之外的任何內容,您都會看到性能損失。 UDF的唯一真正優勢是代碼重用,這對於經過優化的內聯表函數非常適用,並且可以在整個地方使用。但是,我們假設這不會屬於該類別。如果您確實需要實現UDF,請花時間瞭解如何以基於集合的方式執行操作,以便您可以使用內聯表函數。我在下面提供的代碼可以很容易地修改爲使用內聯表函數。

您提到了CROSS APPLY,您沒有在您提供的任何代碼中使用該CROSS APPLY。我不確定您是否意味着您正在使用CROSS APPLY來加入該功能。無論如何,我的理解是,你想離開函數來同時獲得多條記錄。我不知道您的數據,但我猜測這是一個很好的調用,您可以同時在多個NDC上執行此項工作,從而獲得更好的性能。

我創造了一些測試數據(即不只是一個NDC)和變化的東西有點能驗證一切是如何工作的:

DECLARE @myTable TABLE 
    (tableId INT IDENTITY(1,1) PRIMARY KEY CLUSTERED 
    , NDC VARCHAR(11) NOT NULL 
    , ProdDescAbbr VARCHAR(30) NOT NULL 
    , [Description] VARCHAR(30) NOT NULL 
    , Imprint1 VARCHAR(5) NOT NULL 
    , Imprint2 VARCHAR(5) NOT NULL); 

INSERT INTO @myTable VALUES 
    ('00005250033', 'FIBERCON TAB 625MG', 'film-coated', 'LL', 'F 1'), 
    ('00005250033', 'FIBERCON TAB 625MG', 'tan', 'LL', 'F 1'), 
    ('00005250033', 'FIBERCON TAB 625MG', 'scored', 'LQ', 'F 1'), 
    ('00005250033', 'FIBERCON TAB 625MG', 'oblong', 'LL', 'F 2'), 
    ('00005250034', 'FIBERCON TAB 625MG', 'short', '', ''), 
    ('00005250034', 'FIBERCON TAB 625MG', 'green', '', ''), 
    ('00005250035', 'FIBERCON TAB 625MG', 'open', '', ''), 
    ('00005250035', 'FIBERCON TAB 625MG', 'yes', '', ''); 

希望你對錶中的一些主鍵...我冒昧地創造了一個。另外,以最大值取印記而不是具有某種具有可調先驗值的查找表可能有點奇怪,但我們不會花時間評估結構,因爲這不是問題的實質。

在這個例子中(因爲我沒有一個示例查詢,你正在消耗你的函數的結果)我使用cte'cteTemp'來表示無論它將在父查詢中定義你想要哪個NDC瞭解在你的系統中加入該源數據... @myTable在我的例子和dbo.DrugDescriptionAndImprints:

WITH cteTemp AS 
    (
    SELECT * 
    FROM @myTable 
    WHERE NDC IN ('00005250033', '00005250035') 
    ) 
, cteImprints AS 
    (
    SELECT cte.NDC 
     , Imprint1 = MAX(cte.Imprint1) 
     , Imprint2 = MAX(cte.Imprint2) 
    FROM cteTemp AS cte 
    GROUP BY cte.NDC 
    ) 
, cteFinal AS 
    (
    SELECT cte.NDC 
     , Descriptions = STUFF(CONVERT(VARCHAR(1000), 
      (SELECT ',' + sq.[Description] 
      FROM cteTemp AS sq 
      WHERE sq.NDC = cte.NDC 
      ORDER BY sq.[Description] 
      FOR XML PATH (''))), 1, 1, '') 
     , cte.Imprint1 
     , cte.Imprint2 
    FROM cteImprints AS cte 
    ) 
SELECT cte.NDC 
    , concatenatedString = 
     cte.Descriptions + CASE WHEN cte.Imprint1 <> '' OR cte.Imprint2 <> '' THEN ' (' + 
     CASE WHEN cte.Imprint1 <> '' THEN cte.Imprint1 + 
      CASE WHEN cte.Imprint2 <> '' THEN '/' + cte.Imprint2 
      ELSE '' 
      END 
     ELSE cte.Imprint2 END + ')' ELSE '' END 
FROM cteFinal AS cte; 

有一些潛在的性能問題。理想情況下,我們只會從源表(@myTable/dbo.DrugDescriptionAndImprints)讀取一次,然後從此處執行所有操作。這裏的關鍵點是我們可以在一個查詢中獲得最大的印記,但我認爲我們不能避免需要單獨的傳遞來獲取我們想要的每個NDC的描述級聯。你可以使用表變量或臨時表來避免返回源,但通常情況下比接受返回行程更糟糕。但是你必須在你的系統上測試它並評估你的執行計劃,以確定它是否符合你的性能標準。

+0

你是正確的,我正在使用'CROSS APPLY'加入到UDF。我試圖完成的是將NDC的所有「Description」字段合併爲一個值(每個NDC),並且在查詢中使用該值,結果中將包含多個NDC。我會盡力讓你的解決方案適應我的情況,並看看它是如何發展的。謝謝。 –

+0

我已經能夠將CTE應用到我的用例中,而且的確比我之前嘗試做的要快得多。我仍然希望將其清理一些,甚至以某種方式將'concatenatedString'信息移到一個視圖中。 –

+0

普通視圖不會爲性能做任何事情,因爲視圖基本上只是一個子查詢的封裝,在運行時與查詢的其餘部分一起執行。索引視圖可能會提高查詢性能,但也有一些缺點,例如需要進行模式綁定和插入時性能下降。根據數據更改的頻率以及數據在查詢時需要的新鮮度,您可以通過計劃作業進行一些聚合。此外,請檢查您現在的執行計劃,並確保您不缺少任何索引。 – btberry