繁体   English   中英

更新逗号分隔的列

[英]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
更新时:需要时删除并在需要时添加(取决于在关系表中找到的内容)

因为我基本上从不使用逗号分隔的东西,所以我不知道该怎么做。
任何帮助将不胜感激:)

笔记:

  • 不,我不能在应用程序中执行此操作,因为创建文章记录的应用程序无法连接到数据库(它使用一些晦涩的 API),而且由于网络原因,这也是不可能的。
  • 插入、更新和删除的数量非常少(因此我们可以在触发器中执行此操作)
  • 我必须使用逗号分隔的结构,我无法更改 model,因为在此数据库之上运行的应用程序是第 3 方应用程序,我们无法更改,也无法要求修改...
  • 是的,这些表被缩小了,并不是所有的列都在这里,因为它们对这个问题无关紧要

再会,

目前,在每次插入/删除/更新之后,使用 XML FOR PATH 完全更新分隔表。

乍一看这毫无意义...

  1. 如果您编辑用户 x,y,z,那么您应该只更新 [separated] 表中的这些行。 我看不出为什么要更新所有行。

  2. SQL 服务器是一个表格数据库,即使它支持像 XML 和 JSON 这样的非结构化数据,它通常在我们需要解析值时表现不佳。

    您在 [relational] 表中拥有 [separated] 表所需的所有数据。 所以解析每个值是没有意义的。

    你关心什么是当前值? 如果您更改值(添加或删除 ID),则只需使用更改的用户 GUID( 使用插入/删除的逻辑表)使用来自 [relational] 表过滤器的信息更新 [seperated] 表中的值(字符串) )。

1+2 可以使用“UPDATE FROM SELECT”来完成。 您可以使用带有 STRING_AGG function 的简单查询来获取 ID 列表。 不要解析内容,而只需更新(如果需要,替换)并为插入/删除的所有更改的行(并且只有那些更改的行)设置列 [articles] 的值

插入时:添加 ',articleId' 或添加 '@articleId' 如果行为空(不能为空) 删除时:从所有行中删除 articleId 更新时:需要时删除并在需要时添加(取决于在关系表)

同样的问题。 不要解析每种情况的值。 添加 ID 很简单,但删除可能更复杂。 没有理由从字符串中“添加”或“删除”任何内容。 只需将字符串的值更新为每次包含所有相关 ID 的新值。

笔记。 如果您将提供您的代码而不是故事,那么我们可以提供一个工作示例。 您应该提供所有查询以重现整个场景,包括触发器以及您的新旧解决方案/尝试



方法 1(简单的解决方案,最适合删除 ID,在某些情况下适用于所有任务):更新 [seperated] 中的行,这些行在 [relational] 中使用 [inserted] 和 [deleted] 表进行了更改

一般来说,查询应该类似于下面的内容(请记住,这是在 [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
--------------------------------------------------


方法 2(仅适用于添加 ID,在大多数情况下,这是最好的方法,因为我们确实需要聚合 [relational] 表,但只需要聚合插入的表):将 ID 添加到 [seperated] 中已更改的行的现有值在 [relational] 中使用 [inserted] 和 [deleted] 表

如果您想使用将 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM