[英]T-SQL Find Comma Seperated Values IN Tables
零件表
ID名稱兼容型號ID(CS值)
--------- -------------------------
1 Z軸1,2,3
2旋轉1,2,4
3 Rotil 1,2,7
型號表
ID模型
--------
10 3.16
9 5.20
7 3.18
1 7.35
2 8.50
3 X5
4 X6
我需要這個結果
ID零件名稱型號型號(ID)
----------------- ------------- --------------
1個Z-ROT 7.35,8.50,X5 1,2,3
2個ROT 7.35,8.50,X6 1,2,4
3 ROTIL 7.35,8.50,3.18 1,2,7
我怎樣才能做到這一點?
盡管最好使數據庫表至少保持第0個正常形式(沒有重復的組),但是如果您仍然使用現有模式,則可以使用Jeff Moden的Tally-Ho CSV拆分器來解析CSV字段:
CREATE FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
(@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
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
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER()
OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just
-- once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final
-- element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;
go
我強烈建議將表設計更改為每個兼容模型只有一行,最好是一個單獨的表:CompatibleModelsPerPart表
ID PartId CompatibleModelsId
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 4
...
然后,必須拆分“模型”列中的值。 之后,您可以執行內部聯接,如果數據匹配,則可以透視結果集(通常在應用程序層)。
為此,您將需要一個拆分功能...
CREATE FUNCTION [dbo].[split]
(
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
)
RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
INSERT INTO @t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM @xml.nodes('/t') as records(r)
RETURN
END
DECLARE @Part TABLE(ID INT, Name VARCHAR(20), CompatibleModels VARCHAR(20))
INSERT INTO @Part VALUES
(1,'Z-Rot','1,2,3'),
(2,'Rot' ,'1,2,4'),
(3,'Rotil','1,2,7')
DECLARE @Model TABLE(ID INT, Model VARCHAR(20))
INSERT INTO @Model VALUES
(10 ,'3.16'),(9 ,'5.20'),(7 ,'3.18'),(1 ,'7.35')
,(2 ,'8.50'),(3 ,'X5'),(4 ,'X6')
;WITH CTE AS
(
SELECT *
FROM @Part t
CROSS APPLY(SELECT Val FROM dbo.split(t.CompatibleModels,','))C(Model_Ids)
),
CTE2 AS
(
SELECT C.ID
,C.Name AS PartName
,C.CompatibleModels
,M.Model
,Model_Ids
FROM CTE C INNER JOIN @Model M
ON C.Model_Ids = M.ID
)
SELECT ID
,PartName
,STUFF((SELECT ', ' + Model
FROM CTE2
WHERE C2.ID = ID
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1,2,'') AS Model
,C2.CompatibleModels
FROM CTE2 c2
GROUP BY C2.ID, C2.PartName, C2.CompatibleModels
╔════╦══════════╦══════════════════╦═══════════╗
║ ID ║ PartName ║ Model ║ Model_Ids ║
╠════╬══════════╬══════════════════╬═══════════╣
║ 2 ║ Rot ║ 7.35, 8.50, X6 ║ 1, 2, 4 ║
║ 3 ║ Rotil ║ 3.18, 7.35, 8.50 ║ 1, 2, 7 ║
║ 1 ║ Z-Rot ║ 7.35, 8.50, X5 ║ 1, 2, 3 ║
╚════╩══════════╩══════════════════╩═══════════╝
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.