将具有逗号分隔的varchar值的表与SQL Server中另一个表的ID值联接

时间:2019-01-21 10:49:52

标签: sql sql-server stored-procedures sql-server-2014

我有两个表,我们称它们为UsersFruit

用户

ID   Name    Fruit
-------------------
1    Bob      1,3
2    Jack     3

水果

ID   Name
-------------
 1   Apple
 2   Orange
 3   Grape

一个如何将这两个表结合起来以用用户选择的水果名称填充数据表?

我需要编写一个带有循环的存储过程吗?

我对SQL Server还是很陌生,很高兴获得任何帮助或将其指向正确的方向。

5 个答案:

答案 0 :(得分:1)

首先,您需要重新设计表格。需要连接表,该表将保存哪个用户连接到哪个水果。这是N:N的抢夺战。

因此,您应该创建这样的表:

FruitUser

UserId  FruitId
1       1
1       3
2       3

UserId是FK到Users的表,FruitId是FK到Fruits的表,这两个列均构成组合主键。这是一种标准方法。

然后您可以使用简单的联接来获得结果:

select * from users u
join FruitUser fu on u.id = fu.userid
join Fruit f on f.id = fu.fruitId

答案 1 :(得分:1)

对于无法使用SQL Server 2014的{​​{1}},您可以使用STRING_SPLIT拆分varchar,如下所示。

XML

DEMO

答案 2 :(得分:1)

样本数据

DECLARE @Users AS TABLE(ID INt,  Name  VARCHAR(100),fruit VARCHAR(100))
INSERT INTO @Users
SELECT 1,'Bob' ,'1,3' UNION ALL
SELECT 2,'Jack','3'

DECLARE  @Fruit AS TABLE(ID INt,  Name  VARCHAR(100))
INSERT INTO @Fruit
SELECT 1,'Apple' UNION ALL
SELECT 2,'Orange'UNION ALL
SELECT 3,'Grape'

Sql脚本

;WITH CTE
AS
(
SELECT  UserId,
        UserName ,      
        CAST(Split.a.value('.', 'nvarchar(1000)') AS INT) AS FruitId
FROM
(       SELECT  u.ID AS UserId,
                u.Name AS UserName ,      
                CAST( '<S>'+ REPLACE(fruit,',','</S><S>')+'</S>' AS XML) AS FruitId             
        FROM @Fruit f
        INNER JOIN  @Users u
        ON u.ID=f.ID 
)AS A
CROSS APPLY FruitId.nodes('S') AS Split(a)
)
SELECT Userid,
       UserName,
       FruitId,
       ft.name AS FruitName
FROM CTE c
LEFT JOIN (SELECT * FROM @Fruit) AS Ft
ON ft.ID=c.FruitId

结果

Userid  UserName    FruitId   FruitName
------------------------------------------
1        Bob            1       Apple
1        Bob            3       Grape
2        Jack           3       Grape

答案 3 :(得分:0)

通过此查询,您无需更改任何内容即可获得所需的结果

SELECT u.Id, u.Name, f.name  
FROM Users u
inner join Fruit f  on f.ID IN (SELECT cast(value as int)FROM STRING_SPLIT(u.fruit, ','));

由于拥有sql server 2014,因此具有各种选项,如CLR,XML和数字函数。最好的一种是CLR,但它很复杂。因此,您可以使用此XML代码。

select * from
(SELECT ID, [name],LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS fruitid
    FROM
(SELECT ID,[name],CAST('<XMLRoot><RowData>' + REPLACE(fruit,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x FROM  {User table})t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)) u 
inner join {fruit table} f on f.id = u.fruitid

答案 4 :(得分:0)

使用示例数据创建的物理表

CREATE TABLE TempUsers 
( ID INT,
  Name  VARCHAR(100),
  Fruit VARCHAR(100)
 )
INSERT INTO TempUsers 
SELECT 1,'Bob' ,'1,3' UNION ALL
SELECT 2,'Jack','3'

CREATE TABLE TempFruit 
    ( ID INT,
      Name  VARCHAR(100))

INSERT INTO TempFruit
SELECT 1,'Apple' UNION ALL
SELECT 2,'Orange'UNION ALL
SELECT 3,'Grape'

创建一个表值函数,以逗号分隔的形式检索水果名称

CREATE FUNCTION [dbo].[udf_GetFruitNames]
(
@vc_String nvarchar(max)
)
RETURNS  @OutTable TABLE
(
Reqdata nvarchar(max)
)
AS
BEGIN

    DECLARE @Temp AS TABLE
    (
        DATA nvarchar(max)
    )
    INSERT INTO @Temp
    SELECT @vc_String;

    DECLARE @Temp1 AS TABLE
    (
    DATA nvarchar(max)
    )
    INSERT INTO @Temp1
    SELECT 
            STUFF((SELECT DISTINCT ','+ Name FROM
            (
                SELECT  ID,
                        Name    
                FROm TempFruit 
                WHERE ID IN  ( SELECT    
                                    CAST(Split.a.value('.', 'nvarchar(1000)') AS INT) AS FruitId
                                    FROM
                                    (   SELECT    
                                        CAST( '<S>'+ REPLACE(DATA,',','</S><S>')+'</S>' AS XML) AS FruitId             
                                        FROM @Temp f

                                    )AS A
                                    CROSS APPLY FruitId.nodes('S') AS Split(a))
            ) As dt FOR XML PATH ('')),1,1,'') As FruitName


        INSERT INTO @OutTable
        SELECT * FROM @Temp1
RETURN
END

SQL查询

SELECT ID
      ,Name
      ,uf.Reqdata AS FruitNames
FROM TempUsers u
CROSS APPLY [dbo].[udf_GetFruitNames](u.Fruit) AS uf

Or

SELECT ID
  ,Name
  ,(SELECT Reqdata FROM [dbo].[udf_GetFruitNames](u.Fruit) ) AS FruitNames
  FROM TempUsers u

结果

ID  Name    FruitNames
---------------------
1   Bob     Apple,Grape
2   Jack    Grape