我正在尝试使用一组值更新表。数组中的每一项都包含与 SQL Server 数据库表中的行匹配的信息。如果该行已存在于表中,我们将使用给定数组中的信息更新该行。否则,我们在表中插入一个新行。我已经基本上描述了 upsert。
现在,我试图在采用 XML 参数的存储过程中实现这一点。我使用 XML 而不是表值参数的原因是,执行后者时,我必须在 SQL 中创建自定义类型并将此类型与存储过程相关联。如果我以后更改了存储过程或数据库架构中的某些内容,则必须重做存储过程和自定义类型。我想避免这种情况。此外,TVP 相对于 XML 的优势对我的情况没有用,因为我的数据数组大小永远不会超过 1000。这意味着我不能使用这里提出的解决方案:How to insert multiple records using XML in SQL server 2008
此外,这里的类似讨论(UPSERT - 是否有更好的替代 MERGE 或 @@rowcount?)与我所问的不同,因为我试图将多行插入到表中。
我希望我可以简单地使用以下一组查询来更新 xml 中的值。但这行不通。当输入是单行时,这种方法应该有效。
begin tran
update table with (serializable) set select * from xml_param
where key = @key
if @@rowcount = 0
begin
insert table (key, ...) values (@key,..)
end
commit tran
Run Code Online (Sandbox Code Playgroud)
下一个替代方法是使用详尽的 IF EXISTS 或其以下形式的变体之一。但是,我以次优效率为由拒绝了这一点:
IF (SELECT COUNT ... ) > 0 …Run Code Online (Sandbox Code Playgroud) 考虑以下简单的 XML:
<xml>
<customer name="Max">
<email address="me@you.com" />
</customer>
<customer name="Erik">
<email address="erik@your-mom.com" />
</customer>
<customer name="Brent">
<email address="brentcom" />
</customer>
</xml>
Run Code Online (Sandbox Code Playgroud)
我想要得到的名单<Customer>,其中序列address中的属性<email>项并没有包含@。
所以,我希望输出看起来像:
<customer name="Brent">
<email address="brentcom" />
</customer>
Run Code Online (Sandbox Code Playgroud)
麦克维:
DECLARE @x XML = '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';
Run Code Online (Sandbox Code Playgroud)
这个查询:
SELECT WithValidEmail = @x.query('/xml/customer/email[contains(@address, "@")]')
, WithInvalidEmail = @x.query('/xml/customer/email[contains(@address, "@")] = False');
Run Code Online (Sandbox Code Playgroud)
返回:
????????????????????????????????????????????????????????????
? WithValidEmail ? WithInvalidEmail ? …Run Code Online (Sandbox Code Playgroud) 我有这个 tSQL 代码可以正常工作:
SELECT
c.logguid,
a.b.value('./PropertyValue', 'varchar(max)') asd
FROM [dnn].[dbo].[EventLog2] c
cross apply sss.nodes('/LogProperties/LogProperty[PropertyName=sql:variable("@x") and PropertyValue=sql:variable("@y")]') as a(b)
Run Code Online (Sandbox Code Playgroud)
但是,我希望能够做的是传入许多对值的动态列表,这些值对在每个值之间进行 OR 运算,即
SELECT
c.logguid,
a.b.value('./PropertyValue', 'varchar(max)') asd
FROM [dnn].[dbo].[EventLog2] c
cross apply sss.nodes(
'/LogProperties/LogProperty[PropertyName=sql:variable("@x") and PropertyValue=sql:variable("@y")
or
PropertyName=sql:variable("@a") and PropertyValue=sql:variable("@b")
]'
) as a(b)
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?
我正在运行一个查询,该查询正在处理 XML 文档中的一些节点。我估计的子树成本以数百万计,似乎这一切都来自 SQL Server 对我通过 XPath 从 xml 列中提取的某些数据执行的排序操作。Sort 操作的估计行数约为 1900 万,而实际行数约为 800。查询本身运行得相当好(1 - 2 秒),但这种差异让我想知道查询性能以及为什么会这样差别这么大?
据我了解,MS SQL Server Management Studio 不允许通过 GUI 直接编辑/替换 XML 列中的条目(复制/粘贴不起作用等)。
替换 XML 列中单个条目的最简单选项是什么?对于 XML 列值,我是否必须使用与 UPDATE/REPLACE 不同的东西?
我正在尝试查询两个表并获得如下结果:
Section Names
shoes AccountName1, AccountName2, AccountName3
books AccountName1
Run Code Online (Sandbox Code Playgroud)
这些表是:
CREATE TABLE dbo.TableA(ID INT, Section varchar(64), AccountId varchar(64));
INSERT dbo.TableA(ID, Section, AccountId) VALUES
(1 ,'shoes','A1'),
(2 ,'shoes','A2'),
(3 ,'shoes','A3'),
(4 ,'books','A1');
CREATE TABLE dbo.TableB(AccountId varchar(20), Name varchar(64));
INSERT dbo.TableB(AccountId, Name) VALUES
('A1','AccountName1'),
('A2','AccountName2'),
('A3','AccountNAme3');
Run Code Online (Sandbox Code Playgroud)
我看到一些回答说使用“XML PATH”和“STUFF”来查询数据以获得我正在寻找的结果,但我认为缺少一些东西。我尝试了以下查询并收到错误消息:
列“a.AccountId”在选择列表中无效,因为它既不包含在聚合函数中也不包含在 GROUP BY 子句中。
我在任一查询的 SELECT 子句中都没有它,但我认为错误是因为 AccountId 在 TableA 中不是唯一的。
这是我目前正在尝试正常工作的查询。
SELECT section, names= STUFF((
SELECT ', ' + Name FROM TableB as b
WHERE AccountId = b.AccountId
FOR XML PATH('')), 1, 1, …Run Code Online (Sandbox Code Playgroud) 我有一个应用程序,用于存储有关 XML 列中记录的各种用户定义的数据点。我无法控制这些是如何存储或更新的。
当我查询一列时,它可以返回 3 个值中的 1 个:
$64 问题我想使用 xpath 将这些空字符串作为空值返回。
我找到了很多关于将 null 作为空字符串返回的答案,但没有这样的方法。
当有人删除该值时,他们会以这种方式结束,而不是删除标签,而是将其空白到一个<value />标签。当从未设置值时会出现空值。他们没有包括 xsi:nil。
我已经用 case 语句完成了它:
select
so.SalesOrderId,
Case
when sopc.value('(Value)[1]','smalldatetime') IS null then Null
when sopc.value('(Value)[1]','smalldatetime') ='' then Null
Else sopc.value('(Value)[1]','smalldatetime')
End as sopc
From
SalesOrders so
Outer apply so.CustomColumns.nodes('/CustomColumnsCollection/CustomColumn[Name="ProjCompleted"]') sopc(sopc)
Run Code Online (Sandbox Code Playgroud)
但这感觉效率低下,而且这不是唯一的列,因此它使代码变得冗长且难以维护。
编辑以包含示例数据
SalesOrderId CustomColumns
SO 1 "<CustomColumnsCollection>
<CustomColumn>
<Name>ProjCompleted</Name>
<DataType>1</DataType>
<Value />
</CustomColumn>
</CustomColumnsCollection>"
SO 2 "<CustomColumnsCollection>
<CustomColumn>
<Name>ProjCompleted</Name>
<DataType>1</DataType>
<Value>'2017-11-21'</Value>
</CustomColumn>
</CustomColumnsCollection>"
SO 3 "<CustomColumnsCollection>
</CustomColumnsCollection>" …Run Code Online (Sandbox Code Playgroud) 在以下情况下,我没有得到索引查找。而不是<Number>xxx</Number>像这篇文章那样插入到 xml 列中为什么当 where 子句过滤 `value()` 时不使用二级选择性索引?, 用这个 xml 插入 100k 行<SomeText>NiceText</SomeText>和类似数量的 this <SomeText>MoreText</SomeText>。不需要是100k。只需要很多。然后添加索引
create selective xml index SIX_T on dbo.T(XMLDoc) for
(
pathXQUERY = '/SomeText' as xquery 'xs:string' maxlength(8) singleton
);
Run Code Online (Sandbox Code Playgroud)
和二级索引
create xml index SIX_T_pathXQUERY on dbo.T(XMLDoc)
using xml index SIX_T for (pathXQUERY);
Run Code Online (Sandbox Code Playgroud)
然后数数
select count(*)
from dbo.T as T
where T.XMLDoc.exist('/SomeText[. eq "MoreText"]') = 1;
Run Code Online (Sandbox Code Playgroud)
请注意,它不使用索引查找并且“慢”。数百万行可能需要几秒钟。如果我在标准列中插入相同的值并向其添加索引并执行
select count(id)
from dbo.T as T where SomeTextColumn = 'MoreText'
Run Code Online (Sandbox Code Playgroud)
我立即得到结果。在 sql server 18.3.1 …
performance index xml sql-server execution-plan query-performance
我已经设置了一个测试来对 SQL 服务器中的 xml 性能进行基准测试。
测试设置
表和索引设计
CREATE TABLE [dbo].[xml_Test]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[GUID] [varchar](50) NULL,
[JSON_Data] [varchar](max) NULL,
[XML_Data] [xml] NULL,
CONSTRAINT [PK_xml_Test] PRIMARY KEY CLUSTERED ([ID] ASC)
);
ALTER TABLE [dbo].[xml_Test] ADD CONSTRAINT [DF_xml_Test_GUID] DEFAULT (newid()) FOR [GUID];
ALTER TABLE [dbo].[xml_Test] ADD CONSTRAINT [PK_xml_Test] PRIMARY KEY CLUSTERED ([ID] ASC);
CREATE PRIMARY XML INDEX [PK_xml] ON [dbo].[xml_Test]
( [XML_Data]);
CREATE XML INDEX [IX_xml_Path] ON [dbo].[xml_Test] …Run Code Online (Sandbox Code Playgroud) Kenneth Fisher 发表了一篇关于如何确定我的 SSIS 包是什么 SQL 版本的博客文章?2015 年 4 月。
它有一个表,其中列出了哪些 SQL 版本映射到PackageFormatVersion在 XML 元数据中找到的 SSIS 包。这在查看 1 个单独的包时很有用。
我有一个包含大约 100 个 SSIS.DTSX包的文件夹,我需要知道它们都是哪个 SQL 版本。
如何批量确定文件夹(文件系统)中PackageFormatVersion多个.DTSX包的(即 SQL 版本)是什么?
最终目标是确定哪个是正确的 TFS 版本来获取和实施以将这些包放入,因为当前不存在源代码控制系统。Kenneth 提供的表将帮助我回答这个问题,但首先我需要确认包 SQL 版本是什么。
假设我没有安装 BIDS 或 SSDT。
假设所需的输出是这样的,其中管道指定了一个新列:
PackageFilename | PackageFormatVersion
--------------------------------------
Package1.dtsx | 3
Package2.dtsx | 4
Run Code Online (Sandbox Code Playgroud)
欢迎使用 PowerShell、TSQL、可以抓取目录结构的 3rd 方工具或其他工具。
xml ×10
sql-server ×8
t-sql ×4
performance ×3
concat ×1
index ×1
index-tuning ×1
powershell ×1
ssis ×1
upsert ×1
xquery ×1