如何在SQL Server中将详细信息表记录作为字符串获取

时间:2016-12-26 06:18:48

标签: sql sql-server sql-server-2005

我在数据库中有一个表,其中包含医院名称,如下所示:

+------------+--------------+
| HospitalID | HospitalName |
+------------+--------------+
|          1 | Hosp1        |
|          2 | Hosp2        |
|          3 | Hosp3        |
|          4 | Hosp4        |
+------------+--------------+

还存在另一个包含活动名称的表,如下所示:

+------------+--------------+
| ActivityID | ActivityName |
+------------+--------------+
|          1 | Act1         |
|          2 | Act2         |
|          3 | Act3         |
|          4 | Act4         |
|          5 | Act5         |
+------------+--------------+

这些表之间存在N * M关系,即每个医院可以进行不同的活动。因此需要另一个表格如下:

+----+------------+------------+
| ID | HospitalID | ActivityID |
+----+------------+------------+
|  1 |          1 |          1 |
|  2 |          1 |          2 |
|  3 |          1 |          5 |
|  4 |          2 |          1 |
|  5 |          2 |          3 |
|  6 |          3 |          2 |
+----+------------+------------+

我想编写一个select语句,在字符串字段中选择医院名称及其相关活动,如下所示:

+--------------+------------------+
| HospitalName |  ActivityNames   |
+--------------+------------------+
| Hosp1        | Act1, Act2, Act5 |
| Hosp2        | Act1, Act3       |
| Hosp3        | Act2             |
| Hosp4        |                  |
+--------------+------------------+

我使用游标使用ActivityNames字段的函数编写了select语句,但是没有进行优化,系统性能随着记录数量的增加而减少。

有关如何解决此问题的任何解决方案或建议?

3 个答案:

答案 0 :(得分:3)

您只需选择即可完成此操作。不需要循环或光标。循环将使性能降低。

所以Schema将是

CREATE TABLE #HOSPITAL( HOSPITALID INT, HOSPITALNAME VARCHAR(20))

INSERT INTO #HOSPITAL
SELECT 1, 'HOSP1' 
UNION ALL 
SELECT 2 , 'HOSP2' 
UNION ALL 
SELECT 3 ,'HOSP3' 
UNION ALL 
SELECT 4 , 'HOSP4' 



CREATE TABLE #ACTIVITY( ActivityID INT, ActivityName VARCHAR(50) )

INSERT INTO #ACTIVITY                          
SELECT          1,  'Act1'    
UNION ALL     
SELECT          2,  'Act2'  
UNION ALL        
SELECT          3,  'Act3' 
UNION ALL         
SELECT          4,  'Act4'
UNION ALL          
SELECT          5,  'Act5'         


CREATE TABLE #HOSPITAL_ACT_MAP(ID INT, HospitalID INT, ActivityID INT)

INSERT INTO #HOSPITAL_ACT_MAP
SELECT 1, 1, 1 
UNION ALL 
SELECT 2, 1, 2 
UNION ALL 
SELECT 3, 1, 5 
UNION ALL 
SELECT 4, 2, 1 
UNION ALL 
SELECT 5, 2, 3 
UNION ALL 
SELECT 6, 3, 2 

使用CTE选择如下所示

;WITH CTE AS (
SELECT DISTINCT H.HOSPITALNAME, A.ActivityName FROM #HOSPITAL_ACT_MAP HA
INNER JOIN #HOSPITAL H ON HA.HospitalID = H.HOSPITALID
INNER JOIN #ACTIVITY A ON HA.ActivityID = A.ActivityID
)

SELECT  HOSPITALNAME
, (SELECT STUFF((SELECT ','+ActivityName FROM CTE C1 
WHERE  C1.HOSPITALNAME = C.HOSPITALNAME 
FOR XML PATH('')),1,1,'')) 
FROM CTE C
GROUP BY HOSPITALNAME

从评论中修改

如果您无法使用CTEStuff,请选择方法2

DECLARE @TAB TABLE (HOSPITALNAME VARCHAR(20),ActivityName VARCHAR(20) )

INSERT INTO @TAB
SELECT DISTINCT H.HOSPITALNAME, A.ActivityName FROM #HOSPITAL_ACT_MAP HA
INNER JOIN #HOSPITAL H ON HA.HospitalID = H.HOSPITALID
INNER JOIN #ACTIVITY A ON HA.ActivityID = A.ActivityID

SELECT HOSPITALNAME, SUBSTRING(ACTIVITIES,1, LEN(ACTIVITIES)-1) FROM(

SELECT DISTINCT HOSPITALNAME,(SELECT ActivityName+',' FROM @TAB T1 
WHERE  T1.HOSPITALNAME = T.HOSPITALNAME 
FOR XML PATH('') ) AS ACTIVITIES FROM @TAB T

)A

注意:出于性能目的,我已将中间结果存储在@TAB(表变量)上。如果需要,可以使用Sub Query直接查询。

答案 1 :(得分:1)

using STUFF function to achieve your result :

CREATE TABLE #Hospital(HospitalID INT,HospitalName VARCHAR(100))
CREATE TABLE #Activity(ActivityID INT,ActivityName VARCHAR(100))
CREATE TABLE #RelationShip(Id INT,HospId INT,ActId INT)
CREATE TABLE #ConCat(HospitalID  INT ,HospName VARCHAR(100), ActName   
VARCHAR(100),UpFlag TINYINT DEFAULT(0))
DECLARE @HospId INT = 0,@String VARCHAR(200) = ''

INSERT INTO #Hospital(HospitalID ,HospitalName )
SELECT 1,'Hosp1' UNION ALL
SELECT 2,'Hosp2' UNION ALL
SELECT 3,'Hosp3' UNION ALL
SELECT 4,'Hosp4'    

INSERT INTO #Activity(ActivityID ,ActivityName )
SELECT  1,'Act1' UNION ALL 
SELECT  2,'Act2' UNION ALL 
SELECT  3,'Act3' UNION ALL 
SELECT  4,'Act4' UNION ALL 
SELECT  5,'Act5' 

INSERT INTO #RelationShip(ID,HospId,ActId)
SELECT  1 ,          1 ,          1 UNION ALL
SELECT    2 ,          1 ,          2 UNION ALL
SELECT    3 ,          1 ,          5 UNION ALL
SELECT    4 ,          2 ,          1 UNION ALL
SELECT    5 ,          2 ,          3 UNION ALL
SELECT    6 ,          3 ,          2 

SELECT HospitalName , STUFF(  ( SELECT  ',' + ActivityName FROM #Activity   
JOIN #RelationShip ON ActId = ActivityID WHERE HospId = HospitalID FOR XML   
PATH('') ),1,1,'')  
FROM #Hospital
GROUP BY HospitalID,HospitalName 

***FOR SQLServer2005 Use below code***

  INSERT INTO #ConCat (HospitalID ,HospName) 
  SELECT DISTINCT HospitalID ,HospitalName 
  FROM #Hospital

  WHILE EXISTS(SELECT 1 FROM #ConCat WHERE UpFlag = 0)
  BEGIN

     SELECT @HospId =  HospitalID FROM #ConCat WHERE UpFlag = 0 ORDER BY   
     HospitalID

     SET @String = ''
     SELECT @String = ISNULL(@String,'') + CAST(A.ActivityName AS VARCHAR) +    
     ',' FROM 
      (
        SELECT ActivityName 
        FROM #RelationShip 
        JOIN #Activity ON ActId = ActivityID
        WHERE HospId = @HospId
      ) A 

      UPDATE #ConCat SET UpFlag = 1,ActName = CASE WHEN @String = '' THEN    
       @String ELSE SUBSTRING(@String,0,LEN(@String) ) END WHERE HospitalID    
       = @HospId

     END

     SELECT * FROM #ConCat

答案 2 :(得分:0)

您可以使用json来提高前端的性能。 如果您使用的是开源数据库,则没有特别的解决方案。

尝试使用IBM db2或ORACLE数据库来确保应用程序的性能。

然后生成json数据。你会发现速度的提高