我在数据库中有一个表,其中包含医院名称,如下所示:
+------------+--------------+
| 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语句,但是没有进行优化,系统性能随着记录数量的增加而减少。
有关如何解决此问题的任何解决方案或建议?
答案 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
从评论中修改
如果您无法使用CTE
和Stuff
,请选择方法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数据。你会发现速度的提高