我不知道這是否可能在SQL,如果沒有,我會編程方式做到這一點 - 但它會是巨大的,如果有辦法。拆分在SQL一列,然後查找每一個在另一個表
基本上,我有一個表中的列而它與ID的另一個表中的填充,用逗號分隔的 - 這樣一個領域可能是這樣的:
3,4,9
這些鏈接另一個表,其中上面字段中的數字是行的主鍵。在行中是一個描述,我想向用戶顯示而不是數字。
所以基本上,而不是顯示3,4,9給用戶,我想看看他們的相關描述另一個表。這可能嗎?
我不知道這是否可能在SQL,如果沒有,我會編程方式做到這一點 - 但它會是巨大的,如果有辦法。拆分在SQL一列,然後查找每一個在另一個表
基本上,我有一個表中的列而它與ID的另一個表中的填充,用逗號分隔的 - 這樣一個領域可能是這樣的:
3,4,9
這些鏈接另一個表,其中上面字段中的數字是行的主鍵。在行中是一個描述,我想向用戶顯示而不是數字。
所以基本上,而不是顯示3,4,9給用戶,我想看看他們的相關描述另一個表。這可能嗎?
克里斯,
有一個辦法在T-SQL來做到這一點,它實際上是很容易的。首先,你需要創建一個像下面這樣的函數......(使用基於零的「Tally」cte的全新方法,因爲它不會連接任何分隔符,所以它很快速)。
CREATE FUNCTION dbo.DelimitedSplit8KNEW
--===== Created by Jeff Moden (Prototype: Testing Still in Progress)
--===== Define I/O parameters
(
@pString VARCHAR(8000),
@pDelimiter CHAR(1)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
WITH
E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --100
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10,000
cteTally(N) AS (
SELECT 0 UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E4
)
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY t.N),
ItemValue = SUBSTRING(@pString,t.N+1,ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,t.N+1),0),DATALENGTH(@pString)+1)-t.N-1)
FROM cteTally t
WHERE t.N BETWEEN 0 AND DATALENGTH(@pString)
AND (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0)
;
GO
現在,看看如何使用它?讓我們說你有一個唯一的列和您的CSV列的表如下(此建立的數據,以及)。我們所要做的就是CROSS與功能應用原始數據,並奇蹟般地分開準備與另一個表被連接:
--===== This just builds some test data
-- and is not a part of the solution
SELECT *
INTO #TestTable
FROM (
SELECT 1,'3,4,9' UNION ALL
SELECT 2,'3,2,100' UNION ALL
SELECT 3,'14,35,8,21,27,12'
) d (RowNum,CsvValue)
;
--===== Split the data out giving the unique RowNum
-- from the original data, the element position,
-- the the value of the split element. You can
-- join this SELECT with a table to get the other
-- values.
SELECT data.RowNum, split.ItemNumber, split.ItemValue
FROM #TestTable data
CROSS APPLY dbo.DelimitedSplit8KNEW(data.CsvValue,',') split
;
下面是輸出...
RowNum ItemNumber ItemValue
----------- -------------------- ---------
1 1 3
1 2 4
1 3 9
2 1 3
2 2 2
2 3 100
3 1 14
3 2 35
3 3 8
3 4 21
3 5 27
3 6 12
(12 row(s) affected)
您可以編寫表值函數,它的分裂,然後加入您的查找表這一結果。
你有興趣改變你的模式嗎?通常,在單個字段中存儲多個數據是一種可怕的做法。一對多的關係似乎更合適。
可悲的是這是一個現在不可能做出這樣的改變。這是我幾個月以前設計的,當時我第一次成爲程序員,真的爲自己製作這樣一些愚蠢的設計而自責! – Chris 2011-03-04 14:58:59
哈哈,我明白了。我們都會犯這樣的錯誤。有時候,我們可以騰出時間做出這樣的改變來幫助緩解災難,有時候最好的選擇就是簡單地接受它。我希望事情順利。 – FreeAsInBeer 2011-03-04 15:12:14
我看到了這一點,我完全同意。可悲的是,許多人忽視了這樣的好建議,並且實際上允許這種非規範化的數據以XML鼓的形式存儲在表格中。 ;-) – 2012-02-25 22:30:59