SQL Server Obtiene los valores de los tres loggings principales y muestra en una fila por persona

Estoy tratando de get los valores de las tres filas superiores para que una persona se muestre en una fila.

Mi información se ve así:

id co_number client_no Client_name taken_date taken_value -------------------------------------------------------------------------- 270103 12 1111 John Doe 6/7/11 8:45 AM 108 270100 12 1111 John Doe 5/3/11 10:49 AM 109 270097 12 1111 John Doe 4/4/11 1:58 PM 109 270094 12 1111 John Doe 3/1/11 9:04 AM 106 270091 12 1111 John Doe 2/1/11 8:47 AM 105 270088 12 1111 John Doe 1/4/11 9:10 AM 106 270120 12 2222 Jane Smith 6/7/11 9:06 AM 215 270117 12 2222 Jane Smith 5/3/11 2:01 PM 216 270114 12 2222 Jane Smith 4/4/11 2:08 PM 214 270111 12 2222 Jane Smith 3/1/11 9:27 AM 209 270159 12 3333 John Adams 6/7/11 9:45 AM 205 270156 12 3333 John Adams 5/3/11 2:12 PM 203 270153 12 3333 John Adams 4/4/11 1:42 PM 202 270150 12 3333 John Adams 3/1/11 10:32 AM 198 

Quiero que los datos se muestren de esta manera (Date1 es el más reciente, luego Date2, luego Date3):

 co# Name Date1 Value1 Date2 Value2 Date3 Value3 ------------------------------------------------------------------------------------------- 12 John Doe 2011-06-07 08:45 108.0 2011-05-03 10:49 109.0 2011-04-04 13:58 109.0 

Esto es lo que tengo hasta ahora. Funciona pero es lento (tarda 30 segundos para devolver un número de co), así que me pregunto si hay una manera mejor y más eficiente de hacerlo.

 select vmain.co_nmber, vmain.Client_name, vmain.Taken_date, vmain.Taken_value , (select top 1 Taken_date from vital vdate where vdate.co_nmber=vmain.co_nmber and vdate.Medical_Record_Number=vmain.Medical_Record_Number and vdate.Taken_date < vmain.Taken_date order by vdate.Taken_date desc) as date2 , (select top 1 Taken_value from vital v_value where v_value.co_nmber=vmain.co_nmber and v_value.Medical_Record_Number=vmain.Medical_Record_Number and v_value.Taken_date < vmain.Taken_date order by v_value.Taken_date desc) as value2 , (select top 1 Taken_date from vital vdate where vdate.co_nmber=vmain.co_nmber and vdate.Medical_Record_Number=vmain.Medical_Record_Number and vdate.Taken_date < (select top 1 Taken_date from vital vdate where vdate.co_nmber=vmain.co_nmber and vdate.Medical_Record_Number=vmain.Medical_Record_Number and vdate.Taken_date < vmain.Taken_date order by vdate.Taken_date desc) order by vdate.Taken_date desc) as date3 , (select top 1 Taken_value from vital vvalue where vvalue.co_nmber=vmain.co_nmber and vvalue.Medical_Record_Number=vmain.Medical_Record_Number and vvalue.Taken_date < (select top 1 Taken_date from vital vdate where vdate.co_nmber=vmain.co_nmber and vdate.Medical_Record_Number=vmain.Medical_Record_Number and vdate.Taken_date < vmain.Taken_date order by vdate.Taken_date desc) order by vvalue.Taken_date desc) as value3 from vital as vmain inner join( SELECT v.co_nmber, v.Medical_Record_Number, max(v.Taken_date) as Taken_date FROM Vital v and v.co_nmber = 12 GROUP BY v.co_nmber, v.Medical_Record_Number ) as vsub on vsub.co_nmber=vmain.co_nmber and vsub.Medical_Record_Number=vmain.Medical_Record_Number and vsub.Taken_date = vmain.Taken_date and vmain.co_nmber = 12 order by vmain.co_nmber, vmain.Medical_Record_Number, vmain.Taken_date 

Ayuda apreciada.

Puede numerar sus loggings por co y cliente con row_number. Después de esto, puede seleccionar los primeros y juntar los segundos y terceros. Debería ser más rápido.

 with cVital as ( select v.co_nmber, v.Medical_Record_Number, v.Client_name, v.taken_date, v.taken_value, n = row_number() over (partition by v.co_nmber, v.Medical_Record_Number order by v.taken_date desc) from Vital v ) select [co#]=v1.co_nmber, [Name]=v1.Client_name, Date1 = v1.taken_date, Value1 = v1.taken_value, Date2 = v3.taken_date, Value2 = v2.taken_value, Date3 = v2.taken_date, Value3 = v3.taken_value from cVital v1 left join cVital v2 on v2.co_nmber = v1.co_nmber and v2.Medical_Record_Number = v1.Medical_Record_Number and v2.n = 2 left join cVital v3 on v3.co_nmber = v1.co_nmber and v3.Medical_Record_Number = v1.Medical_Record_Number and v3.n = 3 where v1.n = 1 order by v1.co_nmber, v1.Medical_Record_Number; 

La gran pregunta es "¿Qué está haciendo que la consulta se ejecute lentamente?"

¿Su tabla está indexada apropiadamente?

Quizás podría eliminar una de sus columnas calculadas a la vez y ver cómo funciona ese efecto.

La lentitud puede ser el uso de subconsultas correlacionadas en la instrucción Select. Recuerde que las sub-consultas se ejecutarán para cada logging en la tabla

Si solo va a tener un número fijo de valores devueltos utilizando una tabla Temp (o una variable Table) y el método Row_Number () Over funcionará:

 SELECT ROW_NUMBER() OVER (PARTITION BY TheKey ORDER BY DateValue DESC) RowNum, TheKey, DateValue, OtherValue INTO tmp FROM SomeTable WHERE ..... 
 SELECT x1.TheKey, x1.DateValue date1, x1.OtherValue Value1, x2.DateValue Date2, x2.OtherValue Value2, x3.CreateDate Date3, x3.OtherValue Value3 FROM (SELECT * FROM #tmp WHERE rownum=1) x1 left JOIN (SELECT * FROM #tmp WHERE rownum=2) x2 ON x1.TheKey = x2.TheKey left JOIN (SELECT * FROM #tmp WHERE rownum=3) x3 ON x1.TheKey = x3.TheKey 

Ok, actualicé mi respuesta. Aquí hay una solución que funcionará según la consulta que hice anteriormente:

  DECLARE @Name VARCHAR(100) DECLARE @TmpName VARCHAR(100) DECLARE @ID INT DECLARE @CoNum INT DECLARE @Date1 DATETIME DECLARE @Date2 DATETIME DECLARE @Date3 DATETIME DECLARE @Value1 INT DECLARE @Value2 INT DECLARE @Value3 INT DECLARE @IndexValue INT DECLARE @SetValue INT DECLARE @SetDate DATETIME CREATE TABLE #OutputTable ( co_number INT, Client_Name VARCHAR(200), Date1 DATETIME, Value1 INT, Date2 DATETIME, Value2 INT, Date3 DATETIME, Value3 INT ) SELECT DISTINCT Client_name INTO #TempVitalNames FROM vital ORDER BY Client_name WHILE (SELECT COUNT(*) FROM #TempVitalNames) > 0 BEGIN SELECT @IndexValue = 0 SELECT TOP(1) @TmpName = Client_name FROM #TempVitalNames SELECT TOP(3) * INTO #TempVital FROM vital WHERE Client_name = @TmpName ORDER BY taken_date DESC WHILE (@IndexValue < 3) BEGIN SET @Name = (SELECT TOP 1 Client_name FROM #TempVital) SET @CoNum = (SELECT TOP 1 co_number FROM #TempVital) SELECT TOP 1 @ID = id FROM #TempVital SET @SetDate = (SELECT TOP 1 taken_date FROM #TempVital) SET @SetValue = (SELECT TOP 1 taken_value FROM #TempVital) DELETE FROM #TempVital WHERE id = @ID SET @Date1 = CASE WHEN @IndexValue = 0 THEN @SetDate ELSE @Date1 END SET @Date2 = CASE WHEN @IndexValue = 1 THEN @SetDate ELSE @Date2 END SET @Date3 = CASE WHEN @IndexValue = 2 THEN @SetDate ELSE @Date3 END SET @Value1 = CASE WHEN @IndexValue = 0 THEN @SetValue ELSE @Value1 END SET @Value2 = CASE WHEN @IndexValue = 1 THEN @SetValue ELSE @Value2 END SET @Value3 = CASE WHEN @IndexValue = 2 THEN @SetValue ELSE @Value3 END SELECT @IndexValue = @IndexValue + 1 END INSERT INTO #OutputTable (co_number, Client_Name, Date1, Value1, Date2, Value2, Date3, Value3) ( SELECT @CoNum, @Name, @Date1, @Value1, @Date2, @Value2, @Date3, @Value3 ) DELETE #TempVitalNames WHERE Client_name = @TmpName DROP TABlE #TempVital END DROP TABLE #TempVitalNames SELECT * FROM #OutputTable DROP TABLE #OutputTable 

Ok Claudia. Esto primero atraerá todos los nombres únicos de la tabla a una tabla temporal. Luego repetirá a través de cada nombre. Dentro del ciclo de iteración, hará lo que hará mi último progtwig y extraerá las dates necesarias de los 3 primeros nombres e insertá en otra tabla temporal. Después de que todos los nombres hayan sido procesados, entonces volcará el contenido de la tabla temporal, que debería ser el resultado que está buscando. Ejecuté esta consulta en mi sistema con los datos de testing que me proporcionó y se ejecutó en less de 1 segundo. Sé que probablemente tengas muchas más filas con las que tuve que trabajar, pero parece funcionar bastante bien. Si necesita algo más, hágamelo saber y lo modificaré en consecuencia. Puede agregar cualquier tipo de cláusula WHERE adicional a las instrucciones SELECT, si es necesario. Es posible que también necesite cambiar algunos de los types de datos. No estaba seguro de si su valor tomado era integer o decimal o lo que sea. Fui con INT, pero puedes cambiarlo para que coincida con tus necesidades.