0

我的任务是根据设计非常糟糕的表结构创建报告。

考虑以下两个表。它们包含每个人喜欢在每个健身房执行的技术。请记住,一个唯一的人可能会出现在 PERSONNEL 表的多行中:

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 中轻松拆分字符串,但由于 PERSONNEL 表的大小,这不是一个选项。任何人都可以帮忙吗?

4

4 回答 4

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

在这里提琴

于 2013-06-07T21:34:26.237 回答
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
于 2013-06-07T21:29:21.710 回答
0

您必须防止的问题之一是防止“1”匹配“10”和“11”。为此,您要确保所有值都由分隔符(在本例中为逗号)分隔。

这是一种使用like应该有效的方法(尽管性能不会那么好):

SELECT p.*, t.Technique as ParsedTechnique
FROM Personnel p join
     Techniques t
     on ','+p.technique+',' like '%,'+cast(t.id as varchar(255))+',%'
WHERE t.id = 1;

如果性能是一个问题,那么修复您的数据结构并包含一个PersonTechniques表,以便您可以进行正确的连接。

于 2013-06-07T21:54:26.583 回答
0

问题下的第一条评论提供了答案的链接。这是我最终的结果:

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 不匹配。

于 2013-06-08T11:51:45.210 回答