簡體   English   中英

T-SQL在表中查找逗號分隔的值

[英]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

一個使用示例在我的dba.stackexchange帖子中

我強烈建議將表設計更改為每個兼容模型只有一行,最好是一個單獨的表: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.

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