sql - 如何在 SQL Server 中获取明细表记录作为字符串

标签 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 语句,但它没有优化,系统性能会随着记录数量的增加而降低。

关于如何解决这个问题有什么解决方案或建议吗?

最佳答案

您只需选择即可完成此操作。不需要为此循环或游标。循环会使性能下降。

所以架构将是

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(表变量)中。如果需要,可以直接使用子查询对其进行查询。

关于sql - 如何在 SQL Server 中获取明细表记录作为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41327142/

相关文章:

sql - 如何对 SQL 表列进行验证?

c# - 从 sql server 数据库中检索图像

sql-server-2005 - 从 'Y' 或 'N' 转换为位

sql - 根据时间列选择连续事件的计数

sql - 如何将日期时间值从行转换为列

mysql - SQL First() 函数

sql - 如何在 SQL 代理作业中执行存储过程?

mysql - (MySQL) 如何在一个表中连接两列并显示结果?

sql - SSDT 在比较和发布中跳过 NOCHECK 约束

c# - 将数据保存到文本文件并将其加载到 C# 中的数据网格中