在 SQL Server 中添加具有两种数据类型的列
Posted
技术标签:
【中文标题】在 SQL Server 中添加具有两种数据类型的列【英文标题】:Adding columns with two data types in SQL Server 【发布时间】:2017-12-09 11:09:54 【问题描述】:我需要实现这样的输出,任何人都可以帮助我。提前致谢
【问题讨论】:
这违反了 1NF(第一范式),我能想到的原因有两个。 1)您不应该在同一列中有多个数据类型和/或代表不同事物的值。 2) 您不必为了访问列中的值而“解包”数据。 【参考方案1】:如果您的数据格式始终为指定格式,您可以使用left()
& right()
函数
select LEFT(names, 1) [name], SUM(cast(right(names, 2) as int)) [sum] from <table>
group by LEFT(names, 1)
【讨论】:
不适用于给定的数据。投错。冒昧地在我的回答中修正它并引用你的。【参考方案2】:尝试以下方法:
declare @tab table (names varchar(1000))
insert into @tab
select 'a10' union select 'abc20' union select 'xyz5' union select 'b6'
select * from @tab
select names, substring(names, 1, patindex('%[0-9]%',names)-1) [name], substring(names, patindex('%[0-9]%',names), len(names)) [sum]
from @tab
谢谢。
【讨论】:
【参考方案3】:Sql(甚至适用于“a5” - Yogesh Sharma (https://***.com/a/47727953/7505395) 做了艰苦的工作,我修复了它):
select
left(names,1) as name,
sum(cast( right(names,len(names)-1) as int))
from t
group by left(names,1)
测试数据:
CREATE TABLE t ( names varchar(30));
INSERT INTO t ( names ) VALUES ('a10'), ('b20'), ('a5'), ('b6');
结果:
name sum
a 15
b 26
如果前面需要多于一个字符,可以这样做:
select
left(n,idxFirstNum-1) as name,
sum(cast(right(n,len(n)-idxFirstNum+1) as int)) as sum
from (
select
names as n,
PatIndex('%[0-9]%', names) as idxFirstNum
from t
) as tmp
group by left(n,idxFirstNum-1)
它将每个名称的第一个数字的索引存储在内部 tableselect 中,然后在外部 select 中对其进行强制转换/求和/分组。
【讨论】:
【参考方案4】:创建一个类似的函数
Create Function dbo.GetNumbers(@Data VarChar(8000))
Returns VarChar(8000)
AS
Begin
Return Left(
SubString(@Data, PatIndex('%[0-9.-]%', @Data), 8000),
PatIndex('%[^0-9.-]%', SubString(@Data, PatIndex('%[0-9.-]%', @Data), 8000) + 'X')-1)
End
来源Solved Already
如果你想要更多的控制(字符串中有多个数字)最好创建一个 CLR 函数。
使用下面的 T-SQL 获取没有函数的聚合结果:
DROP TABLE IF EXISTS #splitString
CREATE TABLE #splitString(
[columnA] [nchar](10) NULL,
[columnB] [nchar](10) NULL) ON [PRIMARY]
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a10', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a05', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'b20', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a5', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'b9', NULL)
GO
select * from #splitString
select a,sum(b) from (
select
Left(
SubString([columnA], PatIndex('%[a-z.-]%', [columnA]), 8000),
PatIndex('%[^a-z.-]%', SubString([columnA], PatIndex('%[a-z.-]%', [columnA]), 8000) + 'X')-1) a,
cast (Left( SubString([columnA], PatIndex('%[0-9.-]%', [columnA]), 8000),
PatIndex('%[^0-9.-]%', SubString([columnA], PatIndex('%[0-9.-]%', [columnA]), 8000) + 'X')-1) as int) b
From #splitString )aTable group by a
解释(感谢外部链接人)
-
获取第一个字符为 int (PatIndex('%[0-9.-]%', Data))
删除剩下的所有字符 int (SubString(Data, PatIndex('%[0-9.-]%', Data), 8000))
查找数字的结尾(选择 PatIndex('%[^0-9.-]%', SubString(Data, PatIndex('%[0-9.-]%', Data)+1, 8000)) )
获取所有整数 - (Select Left(SubString(Data, PatIndex('%[0-9.-]%', Data), 8000), PatIndex('%[^0-9.-] %', SubString(Data, PatIndex('%[0-9.-]%', Data), 8000) + 'X')-1))
对字符串重复上述过程。
【讨论】:
这个功能并没有解决问题所问的拆分+分组问题,使用了大量的 VarChar 并包含一个非现场链接,你至少应该总结一下,以防它在某个时候消失。你解决了问题的一部分(分裂)——但这本身并不能回答这个问题。 @PatrickArtner 我已根据您的观察对其进行了编辑,我希望看到使用 SQL Server 的更简单的解决方案。 我在我的答案中修复了@YogeshSharmas 错误,并将您的错误转换为更简单的形式 - 不需要函数,更少的 padindexes 并且中间没有子字符串来加速它。我认为您应该考虑解决的问题:您的在.-
处拆分为未要求的数字和数字,您的列名不合适。在大型数据集中使用时,大量的 padindex 和子字符串往往会大大减慢语句的速度。虽然删除了我的 -1 - 你的现在可以使用。我没有 +1,因为它比解决手头问题所需的方式更复杂。以上是关于在 SQL Server 中添加具有两种数据类型的列的主要内容,如果未能解决你的问题,请参考以下文章