SQL 使用 CRM 本地数据使用子查询和连接变量进行查询
SQL query with subquery and concatenating variable using CRM on-premise data
我正在处理一份报告,我需要为特定“activities/tasks”提供注释摘要。
由于activity可以接受多个笔记,所以我必须搜索与activity相关的所有笔记。然后我按日期排序(从新到旧),并将它们与其他一些字符串连接起来:
[Tom Smith wrote on 9/23/2016 1:21 pm] Client was out of office, left message. [Jane Doe wrote on 9/21/2016 3:24 pm] Client called asking about pricing.
数据来自我们内部 CRM 系统的复制表,我使用的是 SQL Server 2012。 我使用的表是: AnnotationBase(包含注释)、ActivityPointerBase(包含 activities/tasks)和 SystemUserID (查找用户名)。由于数据不匹配,我必须对数据类型进行一些转换,以便我可以正确地连接它们,所以这就是为什么有很多 CAST 和 CONVERT。此外,并非所有活动都有与之关联的 NoteText,有时 NoteText 字段为 NULL,因此我必须捕获并过滤掉 NULL(否则它会破坏我的连接字符串)。
我写了下面的查询:
DECLARE @Notes VarChar(Max)
SELECT
( SELECT TOP 5 @Notes = COALESCE(@Notes+ ', ', '') + '[' + CONVERT(varchar(max), ISNULL(sUB.FullName, 'N/A')) + ' wrote on ' + CONVERT(varchar(10), CAST(Anno.ModifiedOn AS DATE), 101) + RIGHT(CONVERT(varchar(32),Anno.ModifiedOn,100),8) + '] ' + CONVERT(varchar(max), ISNULL(Anno.NoteText, '')) --+ CONVERT(varchar(max), CAST(ModifiedOn AS varchar(max)), 101)--+ CAST(ModifiedOn AS varchar(max))
FROM [CRM_rsd].[dbo].[AnnotationBase] AS Anno
LEFT OUTER JOIN [CRM_rsd].[dbo].[systemUserBase] AS sUB
ON Anno.ModifiedBy = sUB.SystemUserId
WHERE Anno.ObjectId = Task.ActivityId--'0B48AB28-C08F-419A-8D98-9916BDFFDE4C'
ORDER BY Anno.ModifiedOn DESC
SELECT LEFT(@Notes,LEN(@Notes)-1)
) AS Notes
,Task.*
FROM [CRM_rsd].[dbo].[ActivityPointerBase] AS Task
WHERE Task.Subject LIKE '%Project On Hold%'
我知道上述方法可能不是很有效,但“搁置项目”列表相当小(少于 500 个),因此性能不是优先事项。优先考虑的是能够为每个 activity 获得一个合并和串联的注释列表。我一直在网上搜索解决方案,并且尝试了很多不同的方法。但是我收到以下错误:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '='.
Msg 102, Level 15, State 1, Line 10
Incorrect syntax near ')'.
我设想了两种可能的解决方案:
- 我的子查询错误已修复或
- 仅创建串联的 NotesText 的“视图”,按 ActivityId(可用作键)分组,然后仅从中查询。
尽管我很确定我的想法会奏效,但我似乎无法弄清楚如何同时连接列和组。
您想要做的是显示来自一个 table 的记录(在您的例子中是 ActivityPointerBase),并且您想要在内部添加一个计算列,其中包含来自另一个 table 的多个记录的信息(在你的情况下 AnnotationBase) 合并在行中。
实现此目的的方法有多种,它们对性能的影响各不相同:
选项 1。您可以编写一个标量函数,该函数接收任务 ID 作为参数,并在 select 前 5 条记录中,以程序方式连接它们并返回 varchar(max)
选项 2:您可以将子查询与 FOR XML 子句结合使用。
SELECT
SUBSTRING(
CAST(
(SELECT TOP 5 ', ' +
'[' + CONVERT(varchar(max), ISNULL(FullName, 'N/A')) +
' wrote on ' +
CONVERT(varchar(10), CAST(ModifiedOn AS DATE), 101) +
RIGHT(CONVERT(varchar(32),ModifiedOn,100),8) + '] ' +
CONVERT(varchar(max), ISNULL(NoteText, ''))
FROM [CRM_rsd].[dbo].[AnnotationBase] AS Anno
LEFT OUTER JOIN [CRM_rsd].[dbo].[systemUserBase] AS sUB ON Anno.ModifiedBy = sUB.SystemUserId
WHERE Anno.ObjectId = Task.ActivityId
ORDER BY Anno.ModifiedOn DESC
FOR XML PATH(''),TYPE
) AS VARCHAR(MAX)
),3,99999) AS Notes
,Task.*
FROM [CRM_rsd].[dbo].[ActivityPointerBase] AS Task
WHERE Task.Subject LIKE '%Project On Hold%'
这里发生的是,通过使用 CAST() 中的构造,我们获取前 5 行并使 SQL 服务器生成一个没有元素名称的 XML,从而导致元素值,我们添加逗号作为分隔符。然后我们将 XML 转换为 varchar(max) 并删除第一条记录之前的初始分隔符。
我更喜欢选项 2,它比使用标量函数的性能要好得多。
我正在处理一份报告,我需要为特定“activities/tasks”提供注释摘要。
由于activity可以接受多个笔记,所以我必须搜索与activity相关的所有笔记。然后我按日期排序(从新到旧),并将它们与其他一些字符串连接起来:
[Tom Smith wrote on 9/23/2016 1:21 pm] Client was out of office, left message. [Jane Doe wrote on 9/21/2016 3:24 pm] Client called asking about pricing.
数据来自我们内部 CRM 系统的复制表,我使用的是 SQL Server 2012。 我使用的表是: AnnotationBase(包含注释)、ActivityPointerBase(包含 activities/tasks)和 SystemUserID (查找用户名)。由于数据不匹配,我必须对数据类型进行一些转换,以便我可以正确地连接它们,所以这就是为什么有很多 CAST 和 CONVERT。此外,并非所有活动都有与之关联的 NoteText,有时 NoteText 字段为 NULL,因此我必须捕获并过滤掉 NULL(否则它会破坏我的连接字符串)。
我写了下面的查询:
DECLARE @Notes VarChar(Max)
SELECT
( SELECT TOP 5 @Notes = COALESCE(@Notes+ ', ', '') + '[' + CONVERT(varchar(max), ISNULL(sUB.FullName, 'N/A')) + ' wrote on ' + CONVERT(varchar(10), CAST(Anno.ModifiedOn AS DATE), 101) + RIGHT(CONVERT(varchar(32),Anno.ModifiedOn,100),8) + '] ' + CONVERT(varchar(max), ISNULL(Anno.NoteText, '')) --+ CONVERT(varchar(max), CAST(ModifiedOn AS varchar(max)), 101)--+ CAST(ModifiedOn AS varchar(max))
FROM [CRM_rsd].[dbo].[AnnotationBase] AS Anno
LEFT OUTER JOIN [CRM_rsd].[dbo].[systemUserBase] AS sUB
ON Anno.ModifiedBy = sUB.SystemUserId
WHERE Anno.ObjectId = Task.ActivityId--'0B48AB28-C08F-419A-8D98-9916BDFFDE4C'
ORDER BY Anno.ModifiedOn DESC
SELECT LEFT(@Notes,LEN(@Notes)-1)
) AS Notes
,Task.*
FROM [CRM_rsd].[dbo].[ActivityPointerBase] AS Task
WHERE Task.Subject LIKE '%Project On Hold%'
我知道上述方法可能不是很有效,但“搁置项目”列表相当小(少于 500 个),因此性能不是优先事项。优先考虑的是能够为每个 activity 获得一个合并和串联的注释列表。我一直在网上搜索解决方案,并且尝试了很多不同的方法。但是我收到以下错误:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '='.
Msg 102, Level 15, State 1, Line 10
Incorrect syntax near ')'.
我设想了两种可能的解决方案:
- 我的子查询错误已修复或
- 仅创建串联的 NotesText 的“视图”,按 ActivityId(可用作键)分组,然后仅从中查询。
尽管我很确定我的想法会奏效,但我似乎无法弄清楚如何同时连接列和组。
您想要做的是显示来自一个 table 的记录(在您的例子中是 ActivityPointerBase),并且您想要在内部添加一个计算列,其中包含来自另一个 table 的多个记录的信息(在你的情况下 AnnotationBase) 合并在行中。
实现此目的的方法有多种,它们对性能的影响各不相同:
选项 1。您可以编写一个标量函数,该函数接收任务 ID 作为参数,并在 select 前 5 条记录中,以程序方式连接它们并返回 varchar(max)
选项 2:您可以将子查询与 FOR XML 子句结合使用。
SELECT
SUBSTRING(
CAST(
(SELECT TOP 5 ', ' +
'[' + CONVERT(varchar(max), ISNULL(FullName, 'N/A')) +
' wrote on ' +
CONVERT(varchar(10), CAST(ModifiedOn AS DATE), 101) +
RIGHT(CONVERT(varchar(32),ModifiedOn,100),8) + '] ' +
CONVERT(varchar(max), ISNULL(NoteText, ''))
FROM [CRM_rsd].[dbo].[AnnotationBase] AS Anno
LEFT OUTER JOIN [CRM_rsd].[dbo].[systemUserBase] AS sUB ON Anno.ModifiedBy = sUB.SystemUserId
WHERE Anno.ObjectId = Task.ActivityId
ORDER BY Anno.ModifiedOn DESC
FOR XML PATH(''),TYPE
) AS VARCHAR(MAX)
),3,99999) AS Notes
,Task.*
FROM [CRM_rsd].[dbo].[ActivityPointerBase] AS Task
WHERE Task.Subject LIKE '%Project On Hold%'
这里发生的是,通过使用 CAST() 中的构造,我们获取前 5 行并使 SQL 服务器生成一个没有元素名称的 XML,从而导致元素值,我们添加逗号作为分隔符。然后我们将 XML 转换为 varchar(max) 并删除第一条记录之前的初始分隔符。
我更喜欢选项 2,它比使用标量函数的性能要好得多。