jdm*_*eon 5 performance sql-server azure-sql-database functions string query-performance
我有一个带有 . 作为分隔符,它看起来像这样......
abc.efg.hij
Run Code Online (Sandbox Code Playgroud)
我想要一个将其转换为三列 Col1、Col2 和 Col3 的查询。我想知道最快的方法是什么。到目前为止,由于我有限的数据库经验,我还没有做得很好。我有一个功能:
CREATE FUNCTION [dbo].[split](
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
INSERT INTO @t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM @xml.nodes('/t') as records(r)
RETURN
END
Run Code Online (Sandbox Code Playgroud)
这就是我现在正在做的事情,但我相信它可以做得更快,我也愿意接受明显更好的功能或用于拆分字符串的开箱即用的想法。我相信我已经运行dbo.split(Name, '.')
了三遍并且只能运行一次。
SELECT
Col1 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '1'),
Col2 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '2'),
Col3 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '3')
FROM Mains
Run Code Online (Sandbox Code Playgroud)
任何帮助将不胜感激
代替:
SELECT
Col1 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '1'),
Col2 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '2'),
Col3 = (SELECT Val from dbo.split(Name, '.') WHERE Id = '3')
FROM Mains
Run Code Online (Sandbox Code Playgroud)
用:
SELECT
s.*
FROM Mains
CROSS APPLY (
SELECT
MAX(CASE WHEN Id = 1 THEN Val END) AS Col1,
MAX(CASE WHEN Id = 2 THEN Val END) AS Col2,
MAX(CASE WHEN Id = 3 THEN Val END) AS Col3
FROM dbo.split(Name,'.') s
) s
Run Code Online (Sandbox Code Playgroud)
这个想法是你仍然希望在 Mains 中每行正好有一行。在内部使用聚合函数CROSS APPLY
就可以做到这一点。通过使用 CASE,您只需split()
每行调用一次。
这里有很多关于拆分字符串的问题,SQL DB 已经string_split()
内置了一个函数。
由于分隔符是一个点,一个非常简洁的方法是
SELECT Col1 = PARSENAME(name,3),
Col2 = PARSENAME(name,2),
Col3 = PARSENAME(name,1)
FROM Mains
Run Code Online (Sandbox Code Playgroud)
以上确实不依赖于任何一个组件部分的长度超过 128 个字符,尽管PARSENAME
它用于解析点分隔的 SQL Server 对象名称,NULL
如果它们不适合SYSNAME
我没有做过任何性能测试。我怀疑下面的效果可能会更好。
SELECT Col1 = LEFT(name, FirstDot - 1),
Col2 = SUBSTRING(name, FirstDot + 1, SecondDot - FirstDot - 1),
Col3 = SUBSTRING(name, 1 + SecondDot, 8000)
FROM Mains
CROSS APPLY (VALUES(CHARINDEX('.', name))) V1(FirstDot)
CROSS APPLY (VALUES(CHARINDEX('.', name, 1 + FirstDot))) V2(SecondDot)
Run Code Online (Sandbox Code Playgroud)