Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL Server表中插入多个值?_Sql_Sql Server_Insert - Fatal编程技术网

如何在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]