Tengo una tabla en la base de datos que contiene los nombres de los hospitales de la siguiente manera:

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

También existe otra tabla que contiene los nombres de las actividades de la siguiente manera:

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

Hay una relación N * M entre estas tablas, es decir, cada hospital puede operar diferentes actividades. Por lo tanto, se requiere otra tabla de la siguiente manera:

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

Quiero escribir una declaración de selección que seleccione los nombres de los hospitales y sus actividades relacionadas en un campo de cadena de la siguiente manera:

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

Escribí la instrucción select usando una función para el campo ActivityNames usando un cursor pero no está optimizada y el rendimiento del sistema disminuye a medida que aumenta el número de registros.

¿Alguna solución o sugerencia sobre cómo resolver este problema?

3
Shahram Akbarinasaji 26 dic. 2016 a las 09:18

3 respuestas

La mejor respuesta

Puede hacer esto solo con una selección. No hay necesidad de bucle o cursor para esto. El bucle hará que el rendimiento se degrade.

Entonces el esquema será

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 

Y seleccione como a continuación con 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

Editar desde comentarios

Si no puede usar CTE y Stuff, vaya al Método 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

Nota: por motivos de rendimiento, he almacenado el resultado intermedio en @TAB (variable de tabla). Si lo desea, puede consultarlo directamente con Subconsulta.

3
Shakeer Mirza 26 dic. 2016 a las 07:32
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
1
Mansoor 26 dic. 2016 a las 07:54

Puede usar json para aumentar el rendimiento del front-end. No existe una solución particular si está utilizando bases de datos de código abierto.

Intente utilizar la base de datos IBM db2 u ORACLE para garantizar el rendimiento de su aplicación.

Luego generar datos json. Encontrará la mejora en velocidad

0
Faruk Kadir 26 dic. 2016 a las 06:35