6 sql t-sql database stored-procedures
我有一张产品表.该表中的每一行对应一个产品,并由唯一的Id标识.现在每个产品可以有多个与该产品相关的"代码".例如:
Id | Code ---------------------- 0001 | IN,ON,ME,OH 0002 | ON,VI,AC,ZO 0003 | QA,PS,OO,ME
我要做的是创建一个存储过程,以便我可以传入像"ON,ME"这样的代码,让它返回包含"ON"或"ME"代码的每个产品.由于代码以逗号分隔,我不知道如何拆分它们并搜索它们.这只能使用TSQL吗?
编辑:这是一个关键任务表.我无权改变它.
Jas*_*yne 11
您应该将代码存储在单独的表中,因为您有多对多的关系.如果你将它们分开,那么你将很容易检查.
可以使用您现在拥有的系统类型,但需要对列进行文本搜索,每行需要多次搜索,这会在数据增长时出现巨大的性能问题.
如果您尝试关闭当前路径:您必须拆分输入字符串,因为没有什么能保证每条记录上的代码与输入参数的顺序相同(或连续).然后你必须做一个
Code LIKE '%IN%'
AND Code Like '%QA%'
Run Code Online (Sandbox Code Playgroud)
查询每个要检查的代码的附加语句.非常低效.
下面的UDF想法也是一个好主意.但是,根据您的数据大小以及查询和更新的频率,您可能也会遇到问题.
是否可以创建一个规范化的附加表,该表在计划的基础上(或基于触发器)进行同步以供您查询?
首先,让我们使原始表变为这样:
Id | Value
-----+------
0001 | IN
0001 | ME
0001 | OH
0001 | ON
0002 | AC
0002 | ON
0002 | VI
0002 | ZO
0003 | ME
0003 | OO
0003 | PS
0003 | QA
Run Code Online (Sandbox Code Playgroud)
它通过将逗号分隔值解析为行来完成.然后使用强大的CROSS APPLY关键字与原始表连接以检索它的Id.下一步就是查询此CTE.
create function FnSplitToTable
(
@param nvarchar(4000)
)
returns table as
return
with
Num(Pos) as -- list of positions, numbered from 1 to 4000, largest nvarchar
(
select cast(1 as int)
union all
select cast(Pos + 1 as int) from Num where Pos < 4000
)
select substring(@Param, Pos,
charindex(',', @Param + ',', Pos) - Pos) as Value
from Num where Pos <= convert(int, len(@Param))
and substring(',' + @Param, Pos, 1) = ','
go
create proc ProcGetProductId
(
@Codes nvarchar(4000)
)
as
with
Src
(
Id,
Code
)
as
(
select '0001', 'IN,ON,ME,OH'
union all
select '0002', 'ON,VI,AC,ZO'
union all
select '0003', 'QA,PS,OO,ME'
),
Parse as
(
select
s.Id,
f.Value
from
Src as s
cross apply
FnSplitToTable(s.Code) as f
)
select distinct
p.Id
from
Parse as p
join
FnSplitToTable(@Codes) as f
on
p.Value = f.Value
option (maxrecursion 4000)
go
exec ProcGetProductId 'IN,ME' -- returns 0001 & 0003
Run Code Online (Sandbox Code Playgroud)
其他人似乎非常渴望告诉你,你不应该这样做,虽然我没有看到任何明确的解释为什么不.
除了违反规范化规则之外,原因是您将对所有行进行表扫描,因为您不能在该列中的单个"值"上有索引.
简单地说,数据库引擎无法保留哪些行包含代码"AC"的某种快速列表,除非您将其分解为单独的表,或者将其单独放入列中.
现在,如果你在你的SELECT语句的其他标准,将行数限制到一些管理的数量,那么也许这将是好的,但除此之外,我想,如果可以的话,尽量避免这种情况的解决方案,并做别人有已经告诉过你,把它分成一个单独的表.
现在,如果您坚持使用此设计,则可以使用以下类型的查询进行搜索:
...
WHERE ',' + Code + ',' LIKE '%,AC,%'
Run Code Online (Sandbox Code Playgroud)
这将:
我不知道在你的情况下最后一个是否是可行的选项,如果你只有2个字母的代码,那么你可以使用这个:
...
WHERE Code LIKE '%AC%'
Run Code Online (Sandbox Code Playgroud)
但同样,除非您使用其他标准限制行数,否则这将执行得非常糟糕.
尽管所有以前的海报是关于你的数据库模式的规范化正确,你可以做你想做什么使用的字符串中需要一个分隔字符串,并返回一个表,其中每行值"表值UDF" ...您可以像使用存储过程中的任何其他表一样使用此表,加入它等...这将解决您的直接问题...
这是这样一个UDF的链接: FN_Split UDF
虽然本文讨论了如何使用它将数据值的分隔列表传递给存储过程,但您可以使用相同的UDF对存储在现有表的列中的分隔字符串进行操作....
归档时间: |
|
查看次数: |
28086 次 |
最近记录: |