如何在SQL Server表中插入多个值?

时间:2014-06-26 10:08:51

标签: sql sql-server insert

我并不完全知道如何表达这个问题,但一个例子可行。所以我有这张桌子

Users

Id          Name
1           Tim
2           Jon
3           Matt

还有另一张表

Tags

TagId       TagName
1           Test
2           Other
3           Dummy
4           More

在临时表中我有这样的结构

TmpUserTags

User            Tags
Tim             Test
Jon             Other, Test
Matt            Dummy, More, Other

所以,我需要做的是从这个临时表中,在表UserTags中插入记录和相应的ID,对于上面给出的例子,结果将是

UserTags

User                TagId
1                   1
2                   2
2                   1
3                   3
3                   4
3                   2 

所以,这是我想要的最终结果,插入UserTags。但是因为对于TmpUserTags中的每一行,每个用户都可以有多个标记,用逗号分隔,我不知道最好的方法是什么。我可以使用while循环(或者更确切地说是游标)循环遍历TmpUserTags中的所有行,然后,对于每一行,用逗号分隔标记,找到它们的Id,并将其插入{{1 }}。但这似乎并不是最优化的方式。有人可以建议一些更好的方法吗?

4 个答案:

答案 0 :(得分:1)

我认为最简单的方法是使用LIKE加入标记列:

CREATE TABLE #Users (ID INT, Name VARCHAR(4));
INSERT #Users (ID, Name)
VALUES (1, 'Tim'), (2, 'Jon'), (3, 'Matt');

CREATE TABLE #Tags (TagID INT, TagName VARCHAR(5));
INSERT #Tags (TagID, TagName)
VALUES (1, 'Test'), (2, 'Other'), (3, 'Dummy'), (4, 'More');

CREATE TABLE #TmpUserTags ([User] VARCHAR(4), Tags VARCHAR(100));
INSERT #tmpUserTags ([User], Tags)
VALUES ('Tim', 'Test'), ('Jon', 'Other,Test'), ('Matt', 'Dummy,More,Other');

SELECT  u.ID, t.TagID 
FROM    #TmpUserTags AS ut
        INNER JOIN #Users AS u
            ON u.Name = ut.[User]
        INNER JOIN #Tags AS t
            ON ',' + ut.Tags + ',' LIKE '%,' + t.TagName + ',%';

您还可以沿着创建分割功能的路线,将逗号分隔列表拆分为行:

CREATE FUNCTION [dbo].[Split](@StringToSplit NVARCHAR(MAX), @Delimiter NCHAR(1))
RETURNS TABLE
AS
RETURN
(   
    SELECT  ID = ROW_NUMBER() OVER(ORDER BY n.Number),
            Position = Number,
            Value = SUBSTRING(@StringToSplit, Number, CHARINDEX(@Delimiter, @StringToSplit + @Delimiter, Number) - Number)
    FROM    (   SELECT  TOP (LEN(@StringToSplit) + 1) Number = ROW_NUMBER() OVER(ORDER BY a.object_id)
                FROM    sys.all_objects a
            ) n
    WHERE   SUBSTRING(@Delimiter + @StringToSplit + @Delimiter, n.Number, 1) = @Delimiter
);

然后你可以使用:

SELECT  u.ID, t.TagID 
FROM    #TmpUserTags AS ut
        CROSS APPLY dbo.Split(ut.tags, ',') AS s
        INNER JOIN #Users AS u
            ON u.Name = ut.[User]
        INNER JOIN #Tags AS t
            ON t.TagName = s.Value;

答案 1 :(得分:0)

这是答案的XML版本:

SELECT Users.Id as [User],Tags.TagId
FROM 
 (SELECT A.[User],  
     LTRIM(Split.a.value('.', 'VARCHAR(100)')) AS Tagname  
 FROM  (SELECT [User],  
         CAST ('<M>' + REPLACE(Tags, ',', '</M><M>') + '</M>' AS XML) AS String  
     FROM  TmpUserTags) AS A CROSS APPLY String.nodes ('/M') AS Split(a)) ut
LEFT JOIN Users ON Users.Name=ut.[User]
LEFT JOIN Tags ON Tags.TagName=ut.Tagname

没有程序,功能和CTE。

[更新] 如果出现一些性能问题,请阅读这篇好文章:http://beyondrelational.com/modules/2/blogs/114/posts/14617/delimited-string-tennis-anyone.aspx

左连接用于显示表TmpUserTags中的所有行,即使其他表没有一些必要的行(例如,新用户&#39; Bob&#39;带标签&#39; Test2&#39;不是&表39中描述了#);

答案 2 :(得分:0)

另一种方法(小提琴:http://sqlfiddle.com/#!3/7f48f/20):

WITH cteTagMatrix
AS
(
    SELECT  n.ID,
            CASE 
                WHEN CHARINDEX(',' + t.TagName + ',', REPLACE(',' + tut.Tags + ',', ' ', '')) <> 0 THEN t.TagID
                ELSE NULL
            END AS TagID
    FROM    Names n INNER JOIN TmpUserTags tut
            ON n.[Name] = tut.[User]
            CROSS JOIN Tags t
)

SELECT    *
FROM      cteTagMatrix
WHERE     TagID IS NOT NULL
ORDER BY  ID, TagID;)

编辑:糟糕,我的逗号逻辑错误。固定代码和小提琴更新。

答案 3 :(得分:0)

对我来说,主要的问题是你如何到达包含逗号分隔列的临时表。如果它是从文件导入并且所有数据都以逗号分隔,那么将文件保存为csv将会很容易,这将分别保存用户和每个标记,然后在数据库中创建一个包含相同数量的表的表如文件所示的列,然后从文件中批量插入此表。

drop table #TmpUserTags
GO
create table #TmpUserTags
(
[user] varchar(10),
tag1 varchar(10),
tag2 varchar(10),
tag3 varchar(10)
)
bulk insert #TmpUserTags from '<filepath>' with (fieldterminator=',')

然后将数据联合起来创建两列,这些列应该很容易重新解释为id。

SELECT [User],Tag1 FROM #TmpUserTags WHERE Tag1 IS NOT NULL
UNION ALL
SELECT [User],Tag2 FROM #TmpUserTags WHERE Tag2 IS NOT NULL
UNION ALL
SELECT [User],Tag3 FROM #TmpUserTags WHERE Tag3 IS NOT NULL
ORDER BY [User]

当然所有这些都可能是猜想,但是,就像 你是如何以逗号分隔的值到达桌面的?