[英]Updating a comma seperated column
我有以下表格:
CREATE TABLE [dbo].[articles]( [ID] [int] IDENTITY(1,1) NOT NULL, [name] [nvarchar](200) NOT NULL, CONSTRAINT [PK_articles] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
✓
CREATE TABLE [dbo].[test_users]( [ID] [int] IDENTITY(1,1) NOT NULL, [GUID] [nvarchar](100) NOT NULL, CONSTRAINT [PK_test_users] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], CONSTRAINT [unique_guid] UNIQUE NONCLUSTERED ( [GUID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
✓
CREATE TABLE [dbo].[relational]( [ID] [int] IDENTITY(1,1) NOT NULL, [articleid] [int] NOT NULL, [userguid] [nvarchar](100) NOT NULL, CONSTRAINT [PK_relational] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] ALTER TABLE [dbo].[relational] WITH CHECK ADD CONSTRAINT [FK_relational_articles] FOREIGN KEY([articleid]) REFERENCES [dbo].[articles] ([ID]) ALTER TABLE [dbo].[relational] CHECK CONSTRAINT [FK_relational_articles] ALTER TABLE [dbo].[relational] WITH CHECK ADD CONSTRAINT [FK_relational_relational] FOREIGN KEY([userguid]) REFERENCES [dbo].[test_users] ([GUID]) ALTER TABLE [dbo].[relational] CHECK CONSTRAINT [FK_relational_relational] GO
✓
CREATE TABLE [dbo].[seperated]( [ID] [int] IDENTITY(1,1) NOT NULL, [userguid] [nvarchar](100) NOT NULL, [articles] [nvarchar](max) NOT NULL, CONSTRAINT [PK_seperated] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] ALTER TABLE [dbo].[seperated] WITH CHECK ADD CONSTRAINT [FK_seperated_test_users] FOREIGN KEY([userguid]) REFERENCES [dbo].[test_users] ([GUID]) ALTER TABLE [dbo].[seperated] CHECK CONSTRAINT [FK_seperated_test_users]
GO
✓
SET IDENTITY_INSERT [dbo].[test_users] ON INSERT [dbo].[test_users] ([ID], [GUID]) VALUES (1, N'guid1') INSERT [dbo].[test_users] ([ID], [GUID]) VALUES (2, N'guid2') INSERT [dbo].[test_users] ([ID], [GUID]) VALUES (3, N'guid3') INSERT [dbo].[test_users] ([ID], [GUID]) VALUES (4, N'guid4') SET IDENTITY_INSERT [dbo].[test_users] OFF GO
4 行受影响
SELECT * FROM [dbo].[test_users] GO
身份证 | GUID -: |:---- 1 | 引导1 2 | 引导2 3 | 指导3 4 | 指导4
SET IDENTITY_INSERT [dbo].[articles] ON INSERT [dbo].[articles] ([ID], [name]) VALUES (1, N'article1') INSERT [dbo].[articles] ([ID], [name]) VALUES (2, N'article2') INSERT [dbo].[articles] ([ID], [name]) VALUES (3, N'article3') SET IDENTITY_INSERT [dbo].[articles] OFF GO
3 行受影响
SELECT * FROM [dbo].[articles] GO
身份证 | 名称 -: |:------- 1 | 文章1 2 | 文章2 3 | 第3条
SET IDENTITY_INSERT [dbo].[relational] ON INSERT [dbo].[relational] ([ID], [articleid], [userguid]) VALUES (1, 1, N'guid1') INSERT [dbo].[relational] ([ID], [articleid], [userguid]) VALUES (2, 1, N'guid2') INSERT [dbo].[relational] ([ID], [articleid], [userguid]) VALUES (3, 2, N'guid2') INSERT [dbo].[relational] ([ID], [articleid], [userguid]) VALUES (4, 1, N'guid3') INSERT [dbo].[relational] ([ID], [articleid], [userguid]) VALUES (5, 3, N'guid3') SET IDENTITY_INSERT [dbo].[relational] OFF GO
5 行受影响
SELECT * FROM [dbo].[relational] GO
身份证 | 文章ID | 用户向导-: | --------: |:-------- 1 | 1 | 引导1 2 | 1 | 引导2 3 | 2 | 指导2 4 | 1 | 引导3 5 | 3 | 引导3
SET IDENTITY_INSERT [dbo].[seperated] ON INSERT [dbo].[seperated] ([ID], [userguid], [articles]) VALUES (1, N'guid1', N'1') INSERT [dbo].[seperated] ([ID], [userguid], [articles]) VALUES (3, N'guid2', N'1,2') INSERT [dbo].[seperated] ([ID], [userguid], [articles]) VALUES (4, N'guid3', N'1,3') INSERT [dbo].[seperated] ([ID], [userguid], [articles]) VALUES (5, N'guid4', N'') SET IDENTITY_INSERT [dbo].[seperated] OFF GO
4 行受影响
SELECT * FROM [dbo].[seperated] GO
身份证 | 用户指南 | 文章 -: |:------- |:------- 1 | 指导1 | 1 3 | 指导2 | 1,2 4 | 引导3 | 1,3 5 | 指导4 |
db<> 在这里摆弄
在文章表上有插入、删除和更新的触发器。
之后需要更新分隔表。
对于每个用户,必须恰好有 1 条记录,以逗号分隔文章(基本上是 user.guid、SELECT * FROM 关系式 WHERE userguid = user.guid)
目前,在每次插入/删除/更新之后,使用 XML FOR PATH 完全更新分隔表。
然而,这不再是一个可行的选择,因为这个操作不够快(关系表中有大约 5 - 1000 万条记录)
为了解决这个问题,我想只为新的/更新的/删除的文章更新分隔表:
在触发器中,我使用@articleId 声明了articleid。
插入时:如果该行为空(不能为空),则添加 ',articleId' 或添加 '@articleId'
删除时:从所有行中删除 articleId
更新时:需要时删除并在需要时添加(取决于在关系表中找到的内容)
因为我基本上从不使用逗号分隔的东西,所以我不知道该怎么做。
任何帮助将不胜感激:)
笔记:
再会,
目前,在每次插入/删除/更新之后,使用 XML FOR PATH 完全更新分隔表。
乍一看这毫无意义...
如果您编辑用户 x,y,z,那么您应该只更新 [separated] 表中的这些行。 我看不出为什么要更新所有行。
SQL 服务器是一个表格数据库,即使它支持像 XML 和 JSON 这样的非结构化数据,它通常在我们需要解析值时表现不佳。
您在 [relational] 表中拥有 [separated] 表所需的所有数据。 所以解析每个值是没有意义的。
你关心什么是当前值? 如果您更改值(添加或删除 ID),则只需使用更改的用户 GUID( 使用插入/删除的逻辑表)使用来自 [relational] 表过滤器的信息更新 [seperated] 表中的值(字符串) )。
1+2 可以使用“UPDATE FROM SELECT”来完成。 您可以使用带有 STRING_AGG function 的简单查询来获取 ID 列表。 不要解析内容,而只需更新(如果需要,替换)并为插入/删除的所有更改的行(并且只有那些更改的行)设置列 [articles] 的值
插入时:添加 ',articleId' 或添加 '@articleId' 如果行为空(不能为空) 删除时:从所有行中删除 articleId 更新时:需要时删除并在需要时添加(取决于在关系表)
同样的问题。 不要解析每种情况的值。 添加 ID 很简单,但删除可能更复杂。 没有理由从字符串中“添加”或“删除”任何内容。 只需将字符串的值更新为每次包含所有相关 ID 的新值。
笔记。 如果您将提供您的代码而不是故事,那么我们可以提供一个工作示例。 您应该提供所有查询以重现整个场景,包括触发器以及您的新旧解决方案/尝试
一般来说,查询应该类似于下面的内容(请记住,这是在 [relational] 表更新后完成的 - 我从该表中读取数据并重新创建已更改行的值)
-------------------------------------------------- Replace
--> assuming that each user has a row in [seperated] even if no id (as described)
;With NyCTE as (
SELECT [userguid], SA = STRING_AGG([articleid], ',')
WITHIN GROUP (ORDER BY [articleid] ASC)
FROM dbo.[relational]
where userguid in (select userguid from inserted)
GROUP BY [userguid]
)
UPDATE [seperated] SET articles = NyCTE.SA
FROM[seperated]
INNER JOIN NyCTE ON NyCTE.userguid = [seperated].userguid
GO
--------------------------------------------------
如果您想使用将 ID 添加到现有字符串的方法(请记住,SQL Server 不会添加或编辑字符串,而是在我们使用 UPDATE 时将其替换掉。
---------------------------------------------------- Add
;With NyCTE as (
SELECT [userguid], SA = STRING_AGG([articleid], ',')
WITHIN GROUP (ORDER BY [articleid] ASC)
FROM dbo.inserted
where userguid in (select userguid from inserted)
GROUP BY [userguid]
)
UPDATE [seperated] SET articles = REPLACE(REPLACE('@' + CONCAT (articles,',', SA), '@,', ''), '@', '')
FROM[seperated]
INNER JOIN NyCTE ON NyCTE.userguid = [seperated].userguid
GO
--------------------------------------------------
- - - - - 更多信息 - - - - - - -
在文章表上有插入、删除和更新的触发器。
请提供完整代码以重现问题(缺少触发器代码)。 总是更喜欢在技术论坛中使用代码而不是故事。
目前,使用 XML FOR PATH 完全更新了分隔表
代码在哪里???
同样,您提供故事而不是代码。
在触发器中,我用@articleId 声明了articleid ...
再次。 您提供故事而不是示例代码。 向我们展示您的工作:提供您测试的代码 :-(
听起来您打算使用循环,这可能是个坏主意,或者更糟糕的是,您计划的解决方案只是为了解决一行更改。 你要插入什么 100k 行???
触发器可能应该与“INSERTED”逻辑表一起使用,并为任务使用简单的 JOIN、EXCEPT 或 INTERSECT。 您应该计划触发器处理数据集而不是单行。
插入时:添加 ',articleId' 或添加 '@articleId' 如果行为空(不能为空)。 删除时:从所有行中删除 articleId。 更新时:需要时删除并在需要时添加(取决于在关系表中找到的内容)
SQL 服务器不要将字符串“添加”到表中的值。 它只能更新整个值。 它可以提前解析值,然后使用 UPDATE 并替换表中的值。 如前所述 SQL 服务器设计用于在关系 model 上获得最佳性能,而不是用于在循环中解析简单字符串。
笔记。 如果您想安全起见,您应该每次都确认这确实是一个新的 id。 如果你这样做,那么你会得到更复杂的任务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.