在 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 中添加具有两种数据类型的列的主要内容,如果未能解决你的问题,请参考以下文章

sql server 小数字段设为哪种类型?

具有类型化数据集和 Sql Server CE 的事务

sql server 数据类型

在SQL-Server中关于日期的数据类型都有哪些?

连接具有空值的汇总数据 - SQL Server

SQL Server中常用的数据类型归类