如何对SQLtable中单个单元格的单词进行排序?
How to sort the words of a single cell in an SQL table?
例如:
- 101 号柱子在公寓里
- 祖祖杜尔加国际酒店
- 温德姆花园 Fresh Meadows
需要将上面的排序为,
- 101 间位于 Pillars 的公寓
- 祖祖杜尔加国际酒店
- Fresh Garden Meadows Wyndham
所以您本机无能为力。如果您想将值排序为 return 值,即不更新数据库本身,您可以使用存储过程或视图转换结果。
那么让我们构建一个答案。
让我们假设您想要在视觉上对一行进行操作。如果你有 SQL 2016 你可以使用 STRING_SPLIT but SQL Fiddle doesn't, so I used a common UDF fnSplitString
http://sqlfiddle.com/#!6/7194d/2
SELECT value
FROM fnSplitString('Pillars 101 in an apartment', ' ')
WHERE RTRIM(value) <> '';
那给了我每个字,拆分出来。订购怎么样?
SELECT value
FROM fnSplitString('Pillars 101 in an apartment', ' ')
WHERE RTRIM(value) <> ''
ORDER BY value;
如果我想对数据库中的每一行执行此操作 table 我有吗? http://sqlfiddle.com/#!6/7194d/8
SELECT split.value
FROM [Data] d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
ORDER BY value;
这很有用,只是现在我所有的话都乱七八糟了。让我们回到原来的查询并识别每一行。每行可能都有一个标识列。如果是这样,那么您的分组就在那里。如果没有,可以使用ROW_NUMBER,如:
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
如果我们随后将此查询用作 select 中的子查询,我们将得到:
http://sqlfiddle.com/#!6/7194d/21
SELECT d.[Identity], split.value
FROM
(
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
) d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
ORDER BY d.[Identity], value;
此查询现在对每个身份中的所有行进行排序。但是现在您需要将这些单独的单词重新构造成一个字符串,对吗?为此,您可以使用 STUFF. In my example I use a CTE because of SQL Fiddle limitations,但您也可以使用临时 table。
WITH tempData AS (
SELECT d.[Identity], split.value
FROM
(
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
) d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
)
SELECT grp.[Identity]
, STUFF((SELECT N' ' + [Value] FROM tempData WHERE [Identity] = grp.[Identity] ORDER BY Value FOR XML PATH(N''))
, 1, 1, N'')
FROM (SELECT DISTINCT [Identity] FROM tempData) AS grp
这是最终结果 fiddle:http://sqlfiddle.com/#!6/7194d/27
如评论中所述,这不是 SQL 的常见情况。这对服务器来说是一种不必要的负担。我建议从 SQL 中提取数据并通过您选择的编程语言对其进行排序;或确保在将其插入数据库时对其进行排序。我完成了练习,因为我有几分钟的时间可以消磨:)
试试这个:
DECLARE @tbl TABLE(YourString VARCHAR(100));
INSERT INTO @tbl VALUES
('Pillars 101 in an apartment')
,('Zuzu Durga International Hotel')
,('Wyndham Garden Fresh Meadows');
SELECT CAST('<x>' + REPLACE((SELECT YourString AS [*] FOR XML PATH('')),' ','</x><x>') + '</x>' AS XML).query
('
for $x in /x
order by $x
return
concat($x/text()[1], " ")
').value('.','varchar(max)')
FROM @tbl;
该代码将首先以 XML 格式传输您的文本,例如 <x>Pillars</x><x>101</x> ...
。
然后一个FLWOR XQuery
用于return排序的文本部分。
最后一次调用 .value()
将 return 排序的片段再次作为文本。
结果
101 Pillars an apartment in
Durga Hotel International Zuzu
Fresh Garden Meadows Wyndham
最终声明
这段代码是一种练习。你的设计真的很糟糕,应该改变...
已经对 Shnugo 的解决方案 +1。其实我也在看他的帖子
另一个选项是将解析 UDF 与交叉应用结合使用。
例子
Select B.*
From YourTable A
Cross Apply ( Select Sorted=Stuff((Select ' ' +RetVal From [dbo].[tvf-Str-Parse](A.SomeCol,' ') Order By RetVal For XML Path ('')),1,1,'') )B
Returns
Sorted
101 an apartment in Pillars
Durga Hotel International Zuzu
Fresh Garden Meadows Wyndham
感兴趣的 UDF
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Thanks Shnugo for making this XML safe
--Select * from [dbo].[tvf-Str-Parse]('Dog,Cat,House,Car',',')
例如:
- 101 号柱子在公寓里
- 祖祖杜尔加国际酒店
- 温德姆花园 Fresh Meadows
需要将上面的排序为,
- 101 间位于 Pillars 的公寓
- 祖祖杜尔加国际酒店
- Fresh Garden Meadows Wyndham
所以您本机无能为力。如果您想将值排序为 return 值,即不更新数据库本身,您可以使用存储过程或视图转换结果。
那么让我们构建一个答案。
让我们假设您想要在视觉上对一行进行操作。如果你有 SQL 2016 你可以使用 STRING_SPLIT but SQL Fiddle doesn't, so I used a common UDF fnSplitString
http://sqlfiddle.com/#!6/7194d/2
SELECT value
FROM fnSplitString('Pillars 101 in an apartment', ' ')
WHERE RTRIM(value) <> '';
那给了我每个字,拆分出来。订购怎么样?
SELECT value
FROM fnSplitString('Pillars 101 in an apartment', ' ')
WHERE RTRIM(value) <> ''
ORDER BY value;
如果我想对数据库中的每一行执行此操作 table 我有吗? http://sqlfiddle.com/#!6/7194d/8
SELECT split.value
FROM [Data] d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
ORDER BY value;
这很有用,只是现在我所有的话都乱七八糟了。让我们回到原来的查询并识别每一行。每行可能都有一个标识列。如果是这样,那么您的分组就在那里。如果没有,可以使用ROW_NUMBER,如:
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
如果我们随后将此查询用作 select 中的子查询,我们将得到:
http://sqlfiddle.com/#!6/7194d/21
SELECT d.[Identity], split.value
FROM
(
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
) d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
ORDER BY d.[Identity], value;
此查询现在对每个身份中的所有行进行排序。但是现在您需要将这些单独的单词重新构造成一个字符串,对吗?为此,您可以使用 STUFF. In my example I use a CTE because of SQL Fiddle limitations,但您也可以使用临时 table。
WITH tempData AS (
SELECT d.[Identity], split.value
FROM
(
SELECT
ROW_NUMBER() OVER(ORDER BY d.Value) AS [Identity] -- here, use identity instead of row_number
, d.Value
FROM [Data] d
) d
CROSS APPLY dbo.fnSplitString(IsNull(d.Value,''), ' ') AS split
WHERE RTRIM(split.value) <> ''
)
SELECT grp.[Identity]
, STUFF((SELECT N' ' + [Value] FROM tempData WHERE [Identity] = grp.[Identity] ORDER BY Value FOR XML PATH(N''))
, 1, 1, N'')
FROM (SELECT DISTINCT [Identity] FROM tempData) AS grp
这是最终结果 fiddle:http://sqlfiddle.com/#!6/7194d/27
如评论中所述,这不是 SQL 的常见情况。这对服务器来说是一种不必要的负担。我建议从 SQL 中提取数据并通过您选择的编程语言对其进行排序;或确保在将其插入数据库时对其进行排序。我完成了练习,因为我有几分钟的时间可以消磨:)
试试这个:
DECLARE @tbl TABLE(YourString VARCHAR(100));
INSERT INTO @tbl VALUES
('Pillars 101 in an apartment')
,('Zuzu Durga International Hotel')
,('Wyndham Garden Fresh Meadows');
SELECT CAST('<x>' + REPLACE((SELECT YourString AS [*] FOR XML PATH('')),' ','</x><x>') + '</x>' AS XML).query
('
for $x in /x
order by $x
return
concat($x/text()[1], " ")
').value('.','varchar(max)')
FROM @tbl;
该代码将首先以 XML 格式传输您的文本,例如 <x>Pillars</x><x>101</x> ...
。
然后一个FLWOR XQuery
用于return排序的文本部分。
最后一次调用 .value()
将 return 排序的片段再次作为文本。
结果
101 Pillars an apartment in
Durga Hotel International Zuzu
Fresh Garden Meadows Wyndham
最终声明
这段代码是一种练习。你的设计真的很糟糕,应该改变...
已经对 Shnugo 的解决方案 +1。其实我也在看他的帖子
另一个选项是将解析 UDF 与交叉应用结合使用。
例子
Select B.*
From YourTable A
Cross Apply ( Select Sorted=Stuff((Select ' ' +RetVal From [dbo].[tvf-Str-Parse](A.SomeCol,' ') Order By RetVal For XML Path ('')),1,1,'') )B
Returns
Sorted
101 an apartment in Pillars
Durga Hotel International Zuzu
Fresh Garden Meadows Wyndham
感兴趣的 UDF
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Thanks Shnugo for making this XML safe
--Select * from [dbo].[tvf-Str-Parse]('Dog,Cat,House,Car',',')