我正在尝试在 SQL Server 2018 中拆分选项值对,到目前为止结果很好,但现在我在 SELECT VALUE FROM STRING_SPLIT()
中遇到了一些奇怪的行为。
代码如下:
SELECT VALUE o FROM STRING_SPLIT('AgingFactorCorr:25',':')
SELECT VALUE o FROM STRING_SPLIT('AlarmBuzSignal:NA',':')
SELECT VALUE o FROM STRING_SPLIT('AgingFactorCorr:25',':') ORDER BY VALUE OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
SELECT VALUE o FROM STRING_SPLIT('AlarmBuzSignal:NA',':') ORDER BY VALUE OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
在运行前两个 SELECT 时,两个对的选项位于第一行,值位于第二行。
然而,当应用 ORDER BY VALUE OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
时,结果是相反的。
对于第一个我选择“25”,对于第二个“AlarmBuzSignal”,需要第二个。
这种行为的原因是什么?除了数据类型之外,看不出任何区别,但我认为这无关紧要。
问题隐藏在 order by 子句中,在添加 LEN(VALUE) DESC 之后,我都得到了想要的结果,但对我来说似乎不是一个优雅的解决方案。
有没有更好的方法来实现这一目标?
任何帮助将不胜感激。
答案 0 :(得分:0)
当您不提供 order by 语句时,行将随机返回,并且行的顺序没有保证。 所以对于你的前两个 select 语句,不能保证行将如何显示
如果您对第一个查询进行排序,结果中的顺序将始终相同
<块引用>SELECT VALUE o FROM STRING_SPLIT('AgingFactorCorr:25',':')ORDER BY VALUE
SELECT VALUE o FROM STRING_SPLIT('AlarmBuzSignal:NA',':') ORDER BY VALUE
SELECT VALUE o FROM STRING_SPLIT('AgingFactorCorr:25',':') ORDER BY VALUE OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
SELECT VALUE o FROM STRING_SPLIT('AlarmBuzSignal:NA',':') ORDER BY VALUE OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
<块引用>
| o | | :-------------- | | 25 | | AgingFactorCorr | | o | | :------------- | | AlarmBuzSignal | | NA | | o | | :- | | 25 | | o | | :------------- | | AlarmBuzSignal |
db<>fiddle here
来自微软文档:
<块引用>输出行可以按任何顺序排列。该顺序不能保证与输入字符串中子字符串的顺序匹配。您可以通过在 SELECT 语句(ORDER BY 值)上使用 ORDER BY 子句来覆盖最终排序顺序。
答案 1 :(得分:0)
您可能想改用手工制作的分割线。它返回一个包含它们位置的子字符串表
CREATE FUNCTION [dbo].[DelimitedSplit8K_LEAD]
(@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(N)
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
Item = SUBSTRING(@pString, s.N1, ISNULL(NULLIF((LEAD(s.N1,1,1) OVER (ORDER BY s.N1)) - 1,0) - s.N1,8000))
FROM cteStart s
;
借自https://www.sqlservercentral.com/articles/reaping-the-benefits-of-the-window-functions-in-t-sql-2
答案 2 :(得分:0)
我找到了适合我的问题的解决方案。
我不处理大数据并且选项值对总是两行,所以我添加了|OPT|在每个选项之前,然后用 replace(o,'|OPT|','')
删除它。
正如答案中提到的,可能有更好的方法来分隔字符串。
我知道我的解决方案在性能方面很重。 将尽我所能改进这一点。