如何在SQL Server表中插入多个值?
我不知道该如何表达这个问题,但举个例子就行了。我有这张桌子如何在SQL Server表中插入多个值?,sql,sql-server,insert,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
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,并将它们插入UserTags中。但这似乎不是最优化的方式。有人能推荐一些更好的方法吗?我认为最简单的方法就是使用如下方式加入标签栏: 您还可以通过创建拆分函数将逗号分隔的列表拆分为行:
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;
以下是答案的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
[更新]如果出现一些性能问题,请阅读以下文章:
Left join用于显示表TmpUserTags中的所有行,即使其他表没有一些必要的行,例如带有标签“Test2”的新用户“Bob”,但标签“Test2”未在表标签中描述,这只是另一种方法:
编辑:哦,是我的逗号逻辑错误。修复了代码和fiddle更新。对我来说,主要问题是如何找到包含逗号分隔列的临时表。如果它是从文件导入的,并且所有数据都是逗号分隔的,那么将文件保存为csv就很容易了,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=',')
当然,所有这些都可能是猜测,但是,您是如何得到带有逗号分隔值的表的?为什么您的TmpUserTags表的结构是这样的?对于每一个元组用户/标记,在行上搜索将非常容易…@RaphaëlAlthaus我知道,但情况并非如此。这与我描述的方式完全一样,对于一个用户,多个逗号分隔的标记。你确定这个like不会对多个标记造成任何问题吗?是的,我有,但我只是问一下,但我以前没有在连接上使用like,似乎过些时候它可能会把事情搞砸。比如说,一个标记是Test,而另一个标记是Test,在这种情况下不会引起问题吗?不,因为谓词在标记名“%”、“+t.TagName+”、“%”中添加了逗号,它将其限制为精确匹配,因此作为tag1的一个示例标记,testing在前后添加了一个逗号,成为tag1,testing,-所以这不会匹配一个test标记,因为它实际上在寻找,test,-它只会匹配,tag1,和,testing,。不,这不是固定的,那里只有3个标记,所以为标记创建一个包含3列的表是行不通的。创建一个表来容纳输入数据中的尽可能多的标记是可以的!它是动态的,不是固定大小的。可能是2可能是200好的,只是为了看看我是否在正确的轨道上,例如,运行此命令将确定您在分隔列中拥有的最大标记数:从tmpusertags中选择maxlentags-lenreplacetags,',',,这看起来有用吗?
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;)
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=',')
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]