从每条记录的逗号分隔值中选择 Min/Max
Selecting Min/Max from Comma Separated Values against each record
考虑以下 table 及其记录
create table dbo.test
(
id numeric(4),
vals nvarchar(1000)
);
insert into dbo.test values (1,'1,2,3,4,5');
insert into dbo.test values (2,'6,7,8,9,0');
insert into dbo.test values (3,'11,54,76,23');
我将使用下面的函数来拆分 CSV,您可以使用任何方法来帮助 select
语法
CREATE FUNCTION [aml].[Split](@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (items varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
我想 select id
和 max
和 min
来自 vals
的值对每条记录。
更新 虽然我在 SQL Server 2008 上编写查询,但我需要支持 SQL Server 2005 及更高版本
您可以 CROSS APPLY
到函数投影的 table,然后对每组 id
应用普通聚合函数:
SELECT t.id, MIN(CAST(x.items AS INT)) AS MinItem, MAX(CAST(x.items AS INT)) AS MaxItem
FROM dbo.test t
CROSS APPLY dbo.Split(t.vals, ',') x
GROUP BY t.id;
(Edit - 因为这些看起来是整数,所以您需要在应用 MIN / MAX
聚合之前进行转换,否则您将得到字母数字排序)
另一种选择是在对其应用查询之前将逗号分隔列表保存在规范化 table 结构中 - 在 RDBMS 中存储非规范化数据没有用:)
没有功能,只是普通sql
:
SELECT t.id,
Max(Split.a.value('.', 'VARCHAR(100)')) AS MaxVal,
Min(Split.a.value('.', 'VARCHAR(100)')) AS MinVal
FROM
(
SELECT id,
CAST ('<M>' + REPLACE(vals, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM test
) AS t CROSS APPLY Data.nodes ('/M') AS Split(a)
group by t.id
select A.id,(select max(item) from dbo.Split(A.vals,',')) as maxvalue,(select 来自 dbo.Split(A.vals,',')) 的 min(item) 作为来自测试 A
的最小值
为 fplit 创建函数
创建函数拆分 (
@InputString VARCHAR(8000),
@Delimiter VARCHAR(50)
)
RETURNS @Items TABLE (
项目 VARCHAR(8000)
)
作为
开始
IF @Delimiter = ' '
开始
SET @Delimiter = ','
SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
结束
IF (@Delimiter IS NULL OR @Delimiter = '')
SET @Delimiter = ','
--INSERT INTO @Items VALUES (@Delimiter) -- 诊断
--INSERT INTO @Items VALUES (@InputString) -- 诊断
DECLARE @Item VARCHAR(8000)
DECLARE @ItemList VARCHAR(8000)
DECLARE @DelimIndex INT
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
WHILE (@DelimIndex != 0)
BEGIN
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
INSERT INTO @Items VALUES (@Item)
-- Set @ItemList = @ItemList minus one less item
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END -- End WHILE
IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
BEGIN
SET @Item = @ItemList
INSERT INTO @Items VALUES (@Item)
END
-- No delimiters were encountered in @InputString, so just return @InputString
ELSE INSERT INTO @Items VALUES (@InputString)
RETURN
END -- 结束函数
去
考虑以下 table 及其记录
create table dbo.test
(
id numeric(4),
vals nvarchar(1000)
);
insert into dbo.test values (1,'1,2,3,4,5');
insert into dbo.test values (2,'6,7,8,9,0');
insert into dbo.test values (3,'11,54,76,23');
我将使用下面的函数来拆分 CSV,您可以使用任何方法来帮助 select
语法
CREATE FUNCTION [aml].[Split](@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (items varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
我想 select id
和 max
和 min
来自 vals
的值对每条记录。
更新 虽然我在 SQL Server 2008 上编写查询,但我需要支持 SQL Server 2005 及更高版本
您可以 CROSS APPLY
到函数投影的 table,然后对每组 id
应用普通聚合函数:
SELECT t.id, MIN(CAST(x.items AS INT)) AS MinItem, MAX(CAST(x.items AS INT)) AS MaxItem
FROM dbo.test t
CROSS APPLY dbo.Split(t.vals, ',') x
GROUP BY t.id;
(Edit - 因为这些看起来是整数,所以您需要在应用 MIN / MAX
聚合之前进行转换,否则您将得到字母数字排序)
另一种选择是在对其应用查询之前将逗号分隔列表保存在规范化 table 结构中 - 在 RDBMS 中存储非规范化数据没有用:)
没有功能,只是普通sql
:
SELECT t.id,
Max(Split.a.value('.', 'VARCHAR(100)')) AS MaxVal,
Min(Split.a.value('.', 'VARCHAR(100)')) AS MinVal
FROM
(
SELECT id,
CAST ('<M>' + REPLACE(vals, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM test
) AS t CROSS APPLY Data.nodes ('/M') AS Split(a)
group by t.id
select A.id,(select max(item) from dbo.Split(A.vals,',')) as maxvalue,(select 来自 dbo.Split(A.vals,',')) 的 min(item) 作为来自测试 A
的最小值为 fplit 创建函数 创建函数拆分 ( @InputString VARCHAR(8000), @Delimiter VARCHAR(50) )
RETURNS @Items TABLE ( 项目 VARCHAR(8000) )
作为 开始 IF @Delimiter = ' ' 开始 SET @Delimiter = ',' SET @InputString = REPLACE(@InputString, ' ', @Delimiter) 结束
IF (@Delimiter IS NULL OR @Delimiter = '')
SET @Delimiter = ','
--INSERT INTO @Items VALUES (@Delimiter) -- 诊断 --INSERT INTO @Items VALUES (@InputString) -- 诊断
DECLARE @Item VARCHAR(8000)
DECLARE @ItemList VARCHAR(8000)
DECLARE @DelimIndex INT
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
WHILE (@DelimIndex != 0)
BEGIN
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
INSERT INTO @Items VALUES (@Item)
-- Set @ItemList = @ItemList minus one less item
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END -- End WHILE
IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
BEGIN
SET @Item = @ItemList
INSERT INTO @Items VALUES (@Item)
END
-- No delimiters were encountered in @InputString, so just return @InputString
ELSE INSERT INTO @Items VALUES (@InputString)
RETURN
END -- 结束函数 去