Sql server 从逗号分隔列表中的一个表中查找主键
我的任务是根据设计非常糟糕的表结构创建报告 考虑以下两个表。它们包含了每个人都喜欢在每个健身房表演的技巧。请记住,唯一的人员可能会出现在人员表的多行上:Sql server 从逗号分隔列表中的一个表中查找主键,sql-server,Sql Server,我的任务是根据设计非常糟糕的表结构创建报告 考虑以下两个表。它们包含了每个人都喜欢在每个健身房表演的技巧。请记住,唯一的人员可能会出现在人员表的多行上: PERSONNEL +-----+-----+-------+--------+-----------+ | ID | PID | Name | Gym | Technique | +-----+-----+-------+--------+-----------+ | 1 | 122 | Bob | GymA | 2,3
PERSONNEL
+-----+-----+-------+--------+-----------+
| ID | PID | Name | Gym | Technique |
+-----+-----+-------+--------+-----------+
| 1 | 122 | Bob | GymA | 2,3,4 |
+-----+-----+-------+--------+-----------+
| 2 | 131 | Mary | GymA | 1,2,4 |
+-----+-----+-------+--------+-----------+
| 3 | 122 | Bob | GymB | 1,2,3 |
+-----+-----+-------+--------+-----------+
TECHNIQUES
+-----+------------+
| ID | Technique |
+-----+------------+
| 1 | Running |
+-----+------------+
| 2 | Walking |
+-----+------------+
| 3 | Hopping |
+-----+------------+
| 4 | Skipping |
+-----+------------+
我遇到的问题是,MSSQL查询将可靠地为我提供表中执行某种技术的每个人的列表
例如,假设我想要一个每个喜欢跳绳的人的列表。预期的结果将是:
PREFERS_SKIPPING
+-----+-------+--------+
| PID | Name | Gym |
+-----+-------+--------+
| 122 | Bob | GymA |
+-----+-------+--------+
| 131 | Mary | GymA |
+-----+-------+--------+
同样地:
PREFERS_HOPPING
+-----+-------+--------+
| PID | Name | Gym |
+-----+-------+--------+
| 122 | Bob | GymA |
+-----+-------+--------+
| 122 | Bob | GymB |
+-----+-------+--------+
我可以在ColdFusion中轻松地断开字符串,但由于人员表的大小,这不是一个选项。有人能帮忙吗?使用此功能
Create FUNCTION F_SplitAsIntTable
(
@txt varchar(max)
)
RETURNS
@tab TABLE
(
ID int
)
AS
BEGIN
declare @i int
declare @s varchar(20)
Set @i = CHARINDEX(',',@txt)
While @i>1
begin
set @s = LEFT(@txt,@i-1)
insert into @tab (id) values (@s)
Set @txt=RIGHT(@txt,Len(@txt)-@i)
Set @i = CHARINDEX(',',@txt)
end
insert into @tab (id) values (@txt)
RETURN
END
您可以这样查询
declare @a Table (id int,Name varchar(10),Kind Varchar(100))
insert into @a values (1,'test','1,2,3,4'),(2,'test2','1,2,3,5'),(3,'test3','3,5')
Select a.ID,Name
from @a a
cross apply F_SplitAsIntTable(a.Kind) b
where b.ID=2
使用此函数
Create FUNCTION F_SplitAsIntTable
(
@txt varchar(max)
)
RETURNS
@tab TABLE
(
ID int
)
AS
BEGIN
declare @i int
declare @s varchar(20)
Set @i = CHARINDEX(',',@txt)
While @i>1
begin
set @s = LEFT(@txt,@i-1)
insert into @tab (id) values (@s)
Set @txt=RIGHT(@txt,Len(@txt)-@i)
Set @i = CHARINDEX(',',@txt)
end
insert into @tab (id) values (@txt)
RETURN
END
您可以这样查询
declare @a Table (id int,Name varchar(10),Kind Varchar(100))
insert into @a values (1,'test','1,2,3,4'),(2,'test2','1,2,3,5'),(3,'test3','3,5')
Select a.ID,Name
from @a a
cross apply F_SplitAsIntTable(a.Kind) b
where b.ID=2
我认为这个查询看起来更清晰:
SELECT p.*,
t.Technique as ParsedTechnique
FROM Personnel p
JOIN Techniques t
ON CHARINDEX((','+CAST(t.id as varchar(10))+','), (','+p.technique+',')) > 0
WHERE t.id ='1';
您只需将WHERE t.id=
更改为所需的TechniqueId
我认为这个查询看起来更清晰:
SELECT p.*,
t.Technique as ParsedTechnique
FROM Personnel p
JOIN Techniques t
ON CHARINDEX((','+CAST(t.id as varchar(10))+','), (','+p.technique+',')) > 0
WHERE t.id ='1';
您只需将WHERE t.id=
更改为所需的TechniqueId
您必须防止的问题之一是阻止“1”匹配“10”和“11”。为此,您需要确保所有值都由分隔符(在本例中为逗号)分隔 下面是一个使用类似于的
的方法,应该可以有效地工作(尽管性能不会那么好):
如果性能有问题,请修复数据结构,包括一个PersonTechniques
表,以便进行正确的连接。必须防止的问题之一是阻止“1”匹配“10”和“11”。为此,您需要确保所有值都由分隔符(在本例中为逗号)分隔
下面是一个使用类似于
的的方法,应该可以有效地工作(尽管性能不会那么好):
如果性能是一个问题,请修复您的数据结构,包括一个PersonTechniques
表,以便您可以进行适当的连接。问题下的第一条注释提供了指向答案的链接。以下是我最终的结果:
WHERE
p.Technique LIKE '%,29,%' --middle
OR
p.Technique LIKE '29,%' --start
OR
p.Technique LIKE '%,29' --end
OR
p.Technique = '29' --single (good point by Cheran S in comment)
乍一看,我认为它不起作用,但巧妙地使用%使它与129等ID不匹配。问题下的第一条评论提供了答案的链接。以下是我最终的结果:
WHERE
p.Technique LIKE '%,29,%' --middle
OR
p.Technique LIKE '29,%' --start
OR
p.Technique LIKE '%,29' --end
OR
p.Technique = '29' --single (good point by Cheran S in comment)
乍一看,我认为这是行不通的,但巧妙地使用%使其与129等ID不匹配。请看一看已被接受的答案,我认为这可能是为您提供一个体面解决方案的起点。这可能很有用,不要在表中存储逗号分隔的数据!我知道不要这样做。。。这是最初安装软件的人员创建的表结构。它在应用程序中根深蒂固,我们不愿意更改它。看起来第一个链接可以很好地工作,虽然乍一看我认为不会。请看一看已被接受的答案,我认为这可能是为您提供一个体面解决方案的起点。也许这会很有用。不要在表中存储逗号分隔的数据!我知道不要这样做。。。这是最初安装软件的人员创建的表结构。它在应用程序中根深蒂固,我们不愿意更改它。看起来第一个链接可以正常工作,虽然乍一看我认为不会。不幸的是,当我将其设置为t.id=1时,使用它会返回t.id=11的匹配项。请参阅我的编辑,您可以通过在id
和技术
列的开头和结尾添加逗号来绕过它。由于一些糟糕的数据库设计,我们一直在使用它,所以这个版本确实有效。这个版本很好用,而且非常干净。我会给你评分。不幸的是,当我将t.id=1设置为t.id=11时,使用它会返回匹配项。请参阅我的编辑,您可以通过在id
和technique
列的开头和结尾添加逗号来绕过这一点。由于一些糟糕的数据库设计,我们一直在使用它,所以这个版本确实有效。这个版本很好用,而且非常干净。我相信你。