none
Pasar datos de una fila a otras RRS feed

  • Pregunta

  • Holas, 

    Les cuento que tengo una tabla que tiene lo siguiente:

    Nombre Nota1 Nota1

    Juan    NULL NULL

    NULL    45      45

    NULL     66     77

    Pedro    NULL NULL

    NULL   85      65

    NULL     69     87

    Y me han pedido que lo transforme a esto:

    Juan    45      45  

    Juan     66     77   

    Pedro   85      65

    Pedro    69     87

    Me pueden dar ideas de cómo hacerlo ?

    jueves, 15 de marzo de 2012 19:22

Respuestas

  • No sé si tiene algún índice agrupado (clustered), así que hay que hacer algunas suposiciones.

    Caso 1:  Sí hay un índice agrupado que contiene un único campo (numérico o no, no importa).  Voy a imaginar que este campo se llama 'ID'.  También el T-SQL que muestro asume un nombre de tabla:  dbo.tblTest.

    En este caso, verifique que la siguiente consulta devuelve un buen resultado:

    With t1 (NumFila, Nombre, Nota1, Nota2)
    As
    (
    	Select
    		Row_Number() Over(Order By ID) As [NumFila]
    		, Nombre
    		, Nota1
    		, Nota2
    	From
    		dbo.tblTest
    )
    , t2 (FilaNombre, Nombre)
    As
    (
    	Select
    		NumFila
    		, Nombre
    	From
    		t1
    	Where
    		Nombre Is Not Null
    )
    Select
    	ot1.*
    	, ot2.FilaNombre
    	, ot2.Nombre As [Nombre Propuesto]
    From
    	t1 As ot1
    	Left Join
    	t2 As ot2
    	On (ot1.NumFila >= ot2.FilaNombre)
    Where
    	ot2.FilaNombre In
    	(
    		Select Max(FilaNombre)
    		From t2
    		Where FilaNombre <= ot1.NumFila
    	)
    ;
    


    Yo lo corrí con sus datos de ejemplo y esto es lo que a mí me muestra:

    NumFila Nombre Nota1 Nota2 FilaNombre Nombre Propuesto

    1 Juan NULL NULL 1 Juan
    2 NULL 45 45 1 Juan
    3 NULL 66 77 1 Juan
    4 Pedro NULL NULL 4 Pedro
    5 NULL 85 65 4 Pedro
    6 NULL 69 87 4 Pedro

    O sea, parece correcto porque el Nombre Propuesto parece coincidir con lo que usted describe que quiere.

    Si todo le parece correcto, la actualización se daría así:

    With t1 (NumFila, ID, Nombre, Nota1, Nota2)
    As
    (
    	Select
    		Row_Number() Over(Order By ID) As [NumFila]
    		, ID
    		, Nombre
    		, Nota1
    		, Nota2
    	From
    		dbo.tblTest
    )
    , t2 (FilaNombre, Nombre)
    As
    (
    	Select
    		NumFila
    		, Nombre
    	From
    		t1
    	Where
    		Nombre Is Not Null
    )
    Update dbo.tblTest
    Set Nombre = ot2.Nombre
    From
        dbo.tblTest
        Inner Join
        t1 As ot1
        On (dbo.tblTest.ID = ot1.ID)
    	Left Join
    	t2 As ot2
    	On (ot1.NumFila >= ot2.FilaNombre)
    Where
    	ot2.FilaNombre In
    	(
    		Select Max(FilaNombre)
    		From t2
    		Where FilaNombre <= ot1.NumFila
    	)
    ;
    

    En este punto, los datos están de esta forma:

    Nombre Nota1 Nota2
    Juan NULL NULL
    Juan 45 45
    Juan 66 77
    Pedro NULL NULL
    Pedro 85 65
    Pedro 69 87

    Lo que resta entonces es borrar los registros con nombre pero sin nota:

    Delete
    From dbo.tblTest
    Where Nota1 Is Null And Nota2 Is Null;

    Caso 2:  No hay índice agrupado.

    En este caso, lo mejor es agregar un nuevo campo temporal llamado NumFila que autonumere las filas:

    Alter Table dbo.tblTest
    Add ID int Not Null Identity(1, 1);

    Ahora con este nuevo campo actuando de mediador, puede usted realizar las consultas mostradas en el caso 1.

    IMPORTANTE:  Siempre pruebe las cosas en desarrollo o QA antes de aplicarlas a producción.  Evite perder o corromper datos.


    Jose R. MCP

    • Propuesto como respuesta webJose martes, 20 de marzo de 2012 13:20
    • Marcado como respuesta Eder Costa jueves, 22 de marzo de 2012 15:00
    viernes, 16 de marzo de 2012 23:07

Todas las respuestas

  • No sé si tiene algún índice agrupado (clustered), así que hay que hacer algunas suposiciones.

    Caso 1:  Sí hay un índice agrupado que contiene un único campo (numérico o no, no importa).  Voy a imaginar que este campo se llama 'ID'.  También el T-SQL que muestro asume un nombre de tabla:  dbo.tblTest.

    En este caso, verifique que la siguiente consulta devuelve un buen resultado:

    With t1 (NumFila, Nombre, Nota1, Nota2)
    As
    (
    	Select
    		Row_Number() Over(Order By ID) As [NumFila]
    		, Nombre
    		, Nota1
    		, Nota2
    	From
    		dbo.tblTest
    )
    , t2 (FilaNombre, Nombre)
    As
    (
    	Select
    		NumFila
    		, Nombre
    	From
    		t1
    	Where
    		Nombre Is Not Null
    )
    Select
    	ot1.*
    	, ot2.FilaNombre
    	, ot2.Nombre As [Nombre Propuesto]
    From
    	t1 As ot1
    	Left Join
    	t2 As ot2
    	On (ot1.NumFila >= ot2.FilaNombre)
    Where
    	ot2.FilaNombre In
    	(
    		Select Max(FilaNombre)
    		From t2
    		Where FilaNombre <= ot1.NumFila
    	)
    ;
    


    Yo lo corrí con sus datos de ejemplo y esto es lo que a mí me muestra:

    NumFila Nombre Nota1 Nota2 FilaNombre Nombre Propuesto

    1 Juan NULL NULL 1 Juan
    2 NULL 45 45 1 Juan
    3 NULL 66 77 1 Juan
    4 Pedro NULL NULL 4 Pedro
    5 NULL 85 65 4 Pedro
    6 NULL 69 87 4 Pedro

    O sea, parece correcto porque el Nombre Propuesto parece coincidir con lo que usted describe que quiere.

    Si todo le parece correcto, la actualización se daría así:

    With t1 (NumFila, ID, Nombre, Nota1, Nota2)
    As
    (
    	Select
    		Row_Number() Over(Order By ID) As [NumFila]
    		, ID
    		, Nombre
    		, Nota1
    		, Nota2
    	From
    		dbo.tblTest
    )
    , t2 (FilaNombre, Nombre)
    As
    (
    	Select
    		NumFila
    		, Nombre
    	From
    		t1
    	Where
    		Nombre Is Not Null
    )
    Update dbo.tblTest
    Set Nombre = ot2.Nombre
    From
        dbo.tblTest
        Inner Join
        t1 As ot1
        On (dbo.tblTest.ID = ot1.ID)
    	Left Join
    	t2 As ot2
    	On (ot1.NumFila >= ot2.FilaNombre)
    Where
    	ot2.FilaNombre In
    	(
    		Select Max(FilaNombre)
    		From t2
    		Where FilaNombre <= ot1.NumFila
    	)
    ;
    

    En este punto, los datos están de esta forma:

    Nombre Nota1 Nota2
    Juan NULL NULL
    Juan 45 45
    Juan 66 77
    Pedro NULL NULL
    Pedro 85 65
    Pedro 69 87

    Lo que resta entonces es borrar los registros con nombre pero sin nota:

    Delete
    From dbo.tblTest
    Where Nota1 Is Null And Nota2 Is Null;

    Caso 2:  No hay índice agrupado.

    En este caso, lo mejor es agregar un nuevo campo temporal llamado NumFila que autonumere las filas:

    Alter Table dbo.tblTest
    Add ID int Not Null Identity(1, 1);

    Ahora con este nuevo campo actuando de mediador, puede usted realizar las consultas mostradas en el caso 1.

    IMPORTANTE:  Siempre pruebe las cosas en desarrollo o QA antes de aplicarlas a producción.  Evite perder o corromper datos.


    Jose R. MCP

    • Propuesto como respuesta webJose martes, 20 de marzo de 2012 13:20
    • Marcado como respuesta Eder Costa jueves, 22 de marzo de 2012 15:00
    viernes, 16 de marzo de 2012 23:07
  • Manuel, ¿le sirvió mi respuesta?

    Jose R. MCP

    martes, 20 de marzo de 2012 13:20