零件表
ID名称兼容型号ID(CS值)
- -------- -------------------------
1 Z-Rot 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 PART NAME型号型号(ID)
- ---------------- ------------- --------------
1 Z-ROT 7.35,8.50,X5 1,2,3
2 ROT 7.35,8.50,X6 1,2,5
3 ROTIL 7.35,8.50,3.18 1,2,7
我怎么能这样做?
答案 0 :(得分:1)
虽然最好将数据库表格保持在至少0正常格式(没有重复的组),但如果您坚持使用现有架构,则可以使用Jeff Moden's Tally-Ho CSV splitter来解析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
答案 1 :(得分:0)
我强烈建议将表格设计更改为每个兼容型号有一行,最好是单独的表格: CompatibleModelsPerPart表
ID PartId CompatibleModelsId
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 4
...
然后必须拆分Models列中的值。之后,您可以执行内部联接,如果数据匹配,您可以旋转结果集(通常在应用程序层)。
答案 2 :(得分:0)
你需要一个分割功能......
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 ║
╚════╩══════════╩══════════════════╩═══════════╝