拆分sql管道分开

时间:2016-03-10 06:44:01

标签: sql sql-server-2008

我有如下表格

Discese

ID | DisceseNAme
1  |  Heart
2  |  Lungs
3  |  ENT

注册

PatienID |  NAME | Discease 
1        | abc   |  1 
2        |  asa  |  2|3
3        |  asd  |  1|2|3

我有一个分割|分隔数据的功能。现在我想要结果为:

PatientID | Name |   DisceseNAme
1         | abc  |   heart
2         |asa   |   Lungs,ENT
3         |asd   |   heart,Lungs,ENT

我的分割功能是

ALTER FUNCTION [dbo].[fnSplit](
    @sInputList VARCHAR(8000) -- List of delimited items
  , @sDelimiter VARCHAR(8000) = '|' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(8000))

BEGIN
DECLARE @sItem VARCHAR(8000)
WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
 BEGIN
 SELECT
  @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
  @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))

 IF LEN(@sItem) > 0
  INSERT INTO @List SELECT @sItem
 END

IF LEN(@sInputList) > 0
 INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END

我不知道如何才能得到那个结果。

1 个答案:

答案 0 :(得分:2)

正如评论中已经提到的,最好规范化表格结构。这意味着您不应将患者的疾病存储在一个VARCHAR列中,疾病ID与某些特征分开。相反,您应该将患者的所有疾病存储在不同的行中。

如果您继续使用现在的设置,您的查询将变得非常麻烦,性能将非常糟糕。此外,您将无法使用外键来享受数据库一致性。

我编写了这个示例脚本,最终选择了您需要的输出。该示例使用临时表。如果您选择使用这种工作方式(并且您应该),只需将此设置与常规表一起使用(即不以#开头)。

表格:

  • #disease:定义疾病
  • #patients:定义患者
  • #registration:定义患者的疾病; #disease#patients的外键用于数据一致性(确保患者和疾病确实存在于数据库中)

如果您想知道最终查询中的FOR XML PATH('')构造如何产生| - 分隔VARCHAR,请阅读this answer我之前就此主题发表过的

-- Diseases
CREATE TABLE #disease(
    ID INT,
    DiseaseName VARCHAR(256),
    CONSTRAINT PK_disease PRIMARY KEY(ID)
);
INSERT INTO #disease(ID,DiseaseName)VALUES
    (1,'Heart'),(2,'Lungs'),(3,'ENT');

-- Patients
CREATE TABLE #patients(
    PatientID INT,
    Name VARCHAR(256),
    CONSTRAINT PK_patients PRIMARY KEY(PatientID)
);
INSERT INTO #patients(PatientID,Name)VALUES
    (1,'abc'),(2,'asa'),(3,'asd'),(4,'zldkzld');

-- Registration for patient's diseases
CREATE TABLE #registration(
    PatientID INT,
    Disease INT,
    CONSTRAINT FK_registration_to_patient FOREIGN KEY(PatientID) REFERENCES #patients(PatientID),
    CONSTRAINT FK_registration_to_disease FOREIGN KEY(Disease) REFERENCES #disease(ID),
);
INSERT INTO #registration(PatientID,Disease)VALUES
    (1,1),             -- patient with ID 1 has one disease: Heart
    (2,2),(2,3),       -- patient with ID 2 has two diseases: Lungs and ENT
    (3,1),(3,2),(3,3); -- patient with ID 3 has three diseases: Heart, Lungs and ENT

-- Select diseases for partients in one |-separated column
SELECT
    p.PatientID,p.Name,Diseases=STUFF(dn.diseases,1,1,'')
FROM
    #patients AS p
    CROSS APPLY ( -- construct a |-separated column with all diseases for the client
        SELECT
            '|'+d.DiseaseName
        FROM
            #registration AS r
            INNER JOIN #disease AS d ON
                d.ID=r.Disease
        WHERE
            r.PatientID=p.PatientID
        FOR
            XML PATH('')
    ) AS dn(diseases)
WHERE
    EXISTS(SELECT 1 FROM #registration AS r WHERE r.PatientID=p.PatientID)
ORDER BY
    p.PatientID;

DROP TABLE #disease;DROP TABLE #registration;DROP TABLE #patients;

结果:

+-----------+------+-----------------+
| PatientID | Name |    Diseases     |
+-----------+------+-----------------+
|         1 | abc  | Heart           |
|         2 | asa  | Lungs|ENT       |
|         3 | asd  | Heart|Lungs|ENT |
+-----------+------+-----------------+