如何在 SQL 服务器中以字符串形式获取详细 table 记录
How to get detail table records as string in SQL Server
我在数据库中有一个 table,其中包含如下医院名称:
+------------+--------------+
| HospitalID | HospitalName |
+------------+--------------+
| 1 | Hosp1 |
| 2 | Hosp2 |
| 3 | Hosp3 |
| 4 | Hosp4 |
+------------+--------------+
还存在另一个 table,其中包含 activity 个名称,如下所示:
+------------+--------------+
| ActivityID | ActivityName |
+------------+--------------+
| 1 | Act1 |
| 2 | Act2 |
| 3 | Act3 |
| 4 | Act4 |
| 5 | Act5 |
+------------+--------------+
这些table之间存在N*M关系,即每个医院可以开展不同的活动。因此需要另一个 table 如下:
+----+------------+------------+
| ID | HospitalID | ActivityID |
+----+------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 5 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
| 6 | 3 | 2 |
+----+------------+------------+
我想写一个 select 语句,其中 select 医院名称及其相关活动在字符串字段中如下:
+--------------+------------------+
| HospitalName | ActivityNames |
+--------------+------------------+
| Hosp1 | Act1, Act2, Act5 |
| Hosp2 | Act1, Act3 |
| Hosp3 | Act2 |
| Hosp4 | |
+--------------+------------------+
我已经使用游标为 ActivityNames 字段使用函数编写了 select 语句,但它没有优化,系统性能会随着记录数量的增加而降低。
关于如何解决这个问题的任何解决方案或建议?
您可以使用json来提高前端的性能。
如果您使用的是开源数据库,则没有特定的解决方案。
尝试使用 IBM db2 或 ORACLE 数据库来确保您的应用程序的性能。
然后生成 json 数据。你会发现速度的提升
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
您只需使用 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
像下面那样 Select
;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(Table 变量)上。如果你想要你可以直接用子查询来查询它。
我在数据库中有一个 table,其中包含如下医院名称:
+------------+--------------+
| HospitalID | HospitalName |
+------------+--------------+
| 1 | Hosp1 |
| 2 | Hosp2 |
| 3 | Hosp3 |
| 4 | Hosp4 |
+------------+--------------+
还存在另一个 table,其中包含 activity 个名称,如下所示:
+------------+--------------+
| ActivityID | ActivityName |
+------------+--------------+
| 1 | Act1 |
| 2 | Act2 |
| 3 | Act3 |
| 4 | Act4 |
| 5 | Act5 |
+------------+--------------+
这些table之间存在N*M关系,即每个医院可以开展不同的活动。因此需要另一个 table 如下:
+----+------------+------------+
| ID | HospitalID | ActivityID |
+----+------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 5 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
| 6 | 3 | 2 |
+----+------------+------------+
我想写一个 select 语句,其中 select 医院名称及其相关活动在字符串字段中如下:
+--------------+------------------+
| HospitalName | ActivityNames |
+--------------+------------------+
| Hosp1 | Act1, Act2, Act5 |
| Hosp2 | Act1, Act3 |
| Hosp3 | Act2 |
| Hosp4 | |
+--------------+------------------+
我已经使用游标为 ActivityNames 字段使用函数编写了 select 语句,但它没有优化,系统性能会随着记录数量的增加而降低。
关于如何解决这个问题的任何解决方案或建议?
您可以使用json来提高前端的性能。 如果您使用的是开源数据库,则没有特定的解决方案。
尝试使用 IBM db2 或 ORACLE 数据库来确保您的应用程序的性能。
然后生成 json 数据。你会发现速度的提升
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
您只需使用 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
像下面那样 Select;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(Table 变量)上。如果你想要你可以直接用子查询来查询它。