Optimizar filtrado en varias tablas

03/05/2007 - 15:59 por Juan Diego Bueno | Informe spam
Hola gente:

Estoy desarrollando actualmente un proyecto en C# 2.0 + SQL Server
2005. El sistema de filtrado que he implementado se basa en una vista
obtenida a partir de una tabla principal (candidatos) y varias
relacionadas con Left outer join.

El tema es que la vista devuelve varias veces el mismo candidato (como
cabría de esperar) en función de las ocurrencias en cada una de las
tablas de relación y con combinación cartesiana, de tal forma que si
por un casual tiene n registros en una, m en otro y así
sucesivamente, puede aparecer n x m x ... veces el mismo candidato, lo
cual cuando la base de datos se cubra con una cantidad considerable de
candidatos y sus datos relacionados, puede dar una vista que devuelva
muchísimos registros.

¿Alguna forma de poder realizar esta consulta de manera que devuelva
los menos registros posibles?. O en su defecto alguna alternativa
eficaz a este sistema.

Gracias de antemano

Saludos

Preguntas similare

Leer las respuestas

#6 Jesús López
04/05/2007 - 11:01 | Informe spam
Yo rediseñaría el formulario, pondría en la parte izquierda un grid que
muestre la lista de candidatos con sus campos más significativos y en la
parte derecha toda la información relativa al candidato que el usuario haya
seleccionado en el grid. En la parte derecha puedes tener varios grids e
incluso fichas (tabs) que el usuario pueda seleccionar para ver la
información. Cuando el el usuario selecciona un candidato entonces ejecutas
una consulta parametrizada por el NIF o Id del candidato seleccionado o un
procedimiento almacenado que obtiene la información relativa a ese
candidato.

Lo de crear campos con múltiples valores por medio de la concatenación es
una buena solución siempre que no sean muchos los valores a concatenar. La
pega es la concatenación es difícil de implementar y poco eficiente (uso de
cursores) en SQL 2000, en SQL 2005 es más sencillo y eficiente, usando
funciones de agregado creadas con CLR o trucos con XML. ¿qué versión usas?.

Saludos:

Jesús López
www.solidqualitylearning.com



"Juan Diego Bueno" escribió en el mensaje
news:eBA4S$
Bien, Jesús, yo estoy de acuerdo pero entonces ¿cómo puedo hacer el
filtrado de forma fácil?. Ten en cuenta que parte de esa vista se va a
mostrar luego en un grid. Lo más parecido que se me ocurre es obtener
mediante filtrado los NIFS en cada una de las tablas y hacer un select
where nif in (listadenifs) pero lo veo más complicado de implementar y
tampoco tengo muy claro cómo. Otra idea que pensé consiste en usar campos
con valores múltiples en la vista, es decir, para cada nif un campo
titulaciones que contenga separadas por comas todas las titulaciones de
ese nif (aunque este tipo de consulta tampoco he pensado como se puede
hacer).

Gracias de antemano

Saludos

"Jesús López" escribió en el mensaje
news:
Mi opinion es que un único conjunto de registros es inadecuado para
describir toda la información requerida. Mi recomendación sería que
usaras varias vistas para obtener toda la información en vez de una sola.

Saludos:

Jesús López
www.solidqualitylearning.com



"Juan Diego Bueno" escribió en el mensaje
news:
Bueno, pensé que con una explicación genérica bastaba, pero aquí
tienes el select de las tablas (obviamente de las tablas base no voy a
mandar el DDL puesto que son unas cuantas, pero es fácilmente
deducible, todas son relaciones M:M)

SELECT
C.NIF, C.APELLIDOS + ', ' + C.NOMBRE AS
NOMBRE_COMPLETO, C.FECHA_NAC, C.TLF_MOVIL, C.TLF_FIJO, C.EMAIL,
C.LOCALIDAD,
P.DEN_PROVINCIA, CASE INTERNO WHEN 1 THEN 'SI'
WHEN 0 THEN 'NO' END AS C_INTERNO, C.INTERNO, C.COD_PROVINCIA,
C.ESTADO_CIVIL,
C.NACIONALIDAD, ISNULL(EC.COD_TITULACION, '') AS
COD_TITULACION, ISNULL(T.COD_NIVEL_TIT, '') AS NIVEL_TITULACION,
EC.FECHA_INI AS FECHA_INI_EST, EC.FECHA_FIN AS
FECHA_FIN_EST, ISNULL(EXC.EMPRESA, '') AS EMPRESA, EXC.FECHA_INI AS
FECHA_INI_EXP,
EXC.FECHA_FIN AS FECHA_FIN_EXP,
ISNULL(EXC.PUESTO, '') AS PUESTO, ISNULL(EXC.DESCRIPCION, '') AS
DESCRIPCION,
ISNULL(ESEST.COD_ESP, '') AS COD_ESP_EST,
ISNULL(ESEST.COD_ANYOS_EXP, 0) AS COD_ANYOS_ESPEST,
ISNULL(ESEXP.COD_ESP, '')
AS COD_ESP_EXP, ISNULL(ESEXP.COD_ANYOS_EXP, 0)
AS COD_ANYOS_ESPEXP, ISNULL(I.COD_IDIOMA, '') AS COD_IDIOMA,
ISNULL(I.LEIDO, '0')
AS LEIDO, ISNULL(I.HABLADO, '0') AS HABLADO,
ISNULL(I.ESCRITO, '0') AS ESCRITO, ISNULL(I.TITULO, '') AS TITULO
FROM dbo.SQL_CANDIDATOS AS C LEFT OUTER JOIN
dbo.SQL_PROVINCIAS AS P ON C.COD_PROVINCIA >> P.COD_PROVINCIA LEFT OUTER JOIN
dbo.SQL_ESTUDIOS_CAND AS EC ON C.NIF = EC.NIF
LEFT OUTER JOIN
dbo.SQL_TITULACIONES AS T ON EC.COD_TITULACION >> T.COD_TITULACION LEFT OUTER JOIN
dbo.SQL_EXPERIENCIA_CAND AS EXC ON C.NIF >> EXC.NIF LEFT OUTER JOIN
dbo.SQL_ESP_EST_CAND AS ESEST ON C.NIF >> ESEST.NIF LEFT OUTER JOIN
dbo.SQL_ESP_EXP_CAND AS ESEXP ON C.NIF >> ESEXP.NIF LEFT OUTER JOIN
dbo.SQL_IDIOMAS_CAND AS I ON C.NIF = I.NIF

Todas las tablas con las que hago el join son tablas de relación de
los candidatos con otras tablas.

El resultado es el esperado... a medias, puesto que si por ejemplo un
candidato tiene varias ocurrencias en SQL_ESTUDIOS_CANS y varias en
SQL_EXPERIENCIA muestra la combinación cartesiana de ambos. Viendo la
cantidad de tablas con las que se relacionan y previendo que cada uno
de los candidatos tenga varios registros relacionados en cada tabla,
la vista podría devolver una cantidad considerable de registros. Busco
otra forma de construir la consulta o alguna alternativa para realizar
el filtrado.

Saludos

On 3 mayo, 16:05, "Maxi" wrote:
Hola, la verdad que no sabemos, y no lo sabemos porque no sabemos que
has
hecho, para poderte ayudar debes mostrarnos que hicistes amigo, es
importante que nos envies:

1) DDL de tablas
2) query
3) Resultados esperados


Salu2

Microsoft MVP SQL Server
Culminis Speaker

"Juan Diego Bueno" escribió en el
mensajenews:
Hola gente:

Estoy desarrollando actualmente un proyecto en C# 2.0 + SQL Server
2005. El sistema de filtrado que he implementado se basa en una vista
obtenida a partir de una tabla principal (candidatos) y varias
relacionadas con Left outer join.

El tema es que la vista devuelve varias veces el mismo candidato (como
cabría de esperar) en función de las ocurrencias en cada una de las
tablas de relación y con combinación cartesiana, de tal forma que si
por un casual tiene n registros en una, m en otro y así
sucesivamente, puede aparecer n x m x ... veces el mismo candidato, lo
cual cuando la base de datos se cubra con una cantidad considerable de
candidatos y sus datos relacionados, puede dar una vista que devuelva
muchísimos registros.

¿Alguna forma de poder realizar esta consulta de manera que devuelva
los menos registros posibles?. O en su defecto alguna alternativa
eficaz a este sistema.

Gracias de antemano

Saludos









Respuesta Responder a este mensaje
#7 Juan Diego Bueno
04/05/2007 - 11:24 | Informe spam
On 4 mayo, 11:01, "Jesús López" wrote:
Yo rediseñaría el formulario, pondría en la parte izquierda un grid que
muestre la lista de candidatos con sus campos más significativos y en la
parte derecha toda la información relativa al candidato que el usuario haya
seleccionado en el grid. En la parte derecha puedes tener varios grids e
incluso fichas (tabs) que el usuario pueda seleccionar para ver la
información. Cuando el el usuario selecciona un candidato entonces ejecutas
una consulta parametrizada por el NIF o Id del candidato seleccionado o un
procedimiento almacenado que obtiene la información relativa a ese
candidato.



Es que el objetivo del formulario es un filtrado general sobre los
candidatos y sus tablas relacionadas. La idea es hacer un AND sobre
los campos que el usuario seleccione y en los casos en los que
proceda, permitir un OR con ocurrencias del mismo campo.


Lo de crear campos con múltiples valores por medio de la concatenación es
una buena solución siempre que no sean muchos los valores a concatenar. La
pega es la concatenación es difícil de implementar y poco eficiente (uso de
cursores) en SQL 2000, en SQL 2005 es más sencillo y eficiente, usando
funciones de agregado creadas con CLR o trucos con XML. ¿qué versión usas?.



Uso SQL 2005

Te cuento lo que he hecho al final, que creo es la solución más
eficiente que se me ha ocurrido.

Creo una vista sobre la tabla principal parametrizando los campos que
no van a permitir más de una ocurrencia (filtrado por nif o por nombre
del candidato)

Creo una vista para cada una de las tablas relacionadas

Ahora supongamos que el usuario ha elegido para el filtrado, dos
titulaciones y tres puestos de trabajo de experiencia, las cuales
están en diferentes tablas de relación. Mediante un sqlcommand, hago
un alter view de la vista de titulaciones añadiendo el filtro que
previamente he generado (ya que aquí no puedo usar parámetros al tener
un cod_titulacion='tit1' or cod_titulacion='tit2'), tres cuartos de lo
mismo con la de la experiencia (espero se me haya entendido)

Ahora hago un alter view de la vista anterior añadiendo dos inner
join, uno por cada una de esas vistas relacionadas

Todavía no lo he acabado de implementar, pero debería funcionar. De
esta forma, sólo genero las vistas que necesite y las uso en la
consulta. Si no necesitara filtrado de ninguna de las tablas
relacionadas, la vista principal quedaría solo con los campos
parametrizados inicialmente.

Tu dirás si es buena opción o no

Saludos
Respuesta Responder a este mensaje
#8 Jesús López
04/05/2007 - 11:32 | Informe spam
Ya he visto que usas SQL 2005.

Para concatenar podrías usar un truco XML. Por ejemplo, la siguiente
consulta devuelve las categorías de la base de datos Northwind, muestra el
idcategoría, el nombre, y en el campo Produts, los nombres de los productos
separados por comas:

SELECT CategoryID, CategoryName,
STUFF((SELECT ', ' + ProductName As [data()]
FROM Products
WHERE CategoryID = C.CategoryID
FOR XML PATH('')),1,1,'') As Products
FROM Categories C

Saludos:

Jesús López
www.solidqualitylearning.com




"Jesús López" escribió en el mensaje
news:
Yo rediseñaría el formulario, pondría en la parte izquierda un grid que
muestre la lista de candidatos con sus campos más significativos y en la
parte derecha toda la información relativa al candidato que el usuario
haya seleccionado en el grid. En la parte derecha puedes tener varios
grids e incluso fichas (tabs) que el usuario pueda seleccionar para ver la
información. Cuando el el usuario selecciona un candidato entonces
ejecutas una consulta parametrizada por el NIF o Id del candidato
seleccionado o un procedimiento almacenado que obtiene la información
relativa a ese candidato.

Lo de crear campos con múltiples valores por medio de la concatenación es
una buena solución siempre que no sean muchos los valores a concatenar. La
pega es la concatenación es difícil de implementar y poco eficiente (uso
de cursores) en SQL 2000, en SQL 2005 es más sencillo y eficiente, usando
funciones de agregado creadas con CLR o trucos con XML. ¿qué versión
usas?.

Saludos:

Jesús López
www.solidqualitylearning.com



"Juan Diego Bueno" escribió en el mensaje
news:eBA4S$
Bien, Jesús, yo estoy de acuerdo pero entonces ¿cómo puedo hacer el
filtrado de forma fácil?. Ten en cuenta que parte de esa vista se va a
mostrar luego en un grid. Lo más parecido que se me ocurre es obtener
mediante filtrado los NIFS en cada una de las tablas y hacer un select
where nif in (listadenifs) pero lo veo más complicado de implementar y
tampoco tengo muy claro cómo. Otra idea que pensé consiste en usar campos
con valores múltiples en la vista, es decir, para cada nif un campo
titulaciones que contenga separadas por comas todas las titulaciones de
ese nif (aunque este tipo de consulta tampoco he pensado como se puede
hacer).

Gracias de antemano

Saludos

"Jesús López" escribió en el mensaje
news:
Mi opinion es que un único conjunto de registros es inadecuado para
describir toda la información requerida. Mi recomendación sería que
usaras varias vistas para obtener toda la información en vez de una
sola.

Saludos:

Jesús López
www.solidqualitylearning.com



"Juan Diego Bueno" escribió en el mensaje
news:
Bueno, pensé que con una explicación genérica bastaba, pero aquí
tienes el select de las tablas (obviamente de las tablas base no voy a
mandar el DDL puesto que son unas cuantas, pero es fácilmente
deducible, todas son relaciones M:M)

SELECT
C.NIF, C.APELLIDOS + ', ' + C.NOMBRE AS
NOMBRE_COMPLETO, C.FECHA_NAC, C.TLF_MOVIL, C.TLF_FIJO, C.EMAIL,
C.LOCALIDAD,
P.DEN_PROVINCIA, CASE INTERNO WHEN 1 THEN 'SI'
WHEN 0 THEN 'NO' END AS C_INTERNO, C.INTERNO, C.COD_PROVINCIA,
C.ESTADO_CIVIL,
C.NACIONALIDAD, ISNULL(EC.COD_TITULACION, '') AS
COD_TITULACION, ISNULL(T.COD_NIVEL_TIT, '') AS NIVEL_TITULACION,
EC.FECHA_INI AS FECHA_INI_EST, EC.FECHA_FIN AS
FECHA_FIN_EST, ISNULL(EXC.EMPRESA, '') AS EMPRESA, EXC.FECHA_INI AS
FECHA_INI_EXP,
EXC.FECHA_FIN AS FECHA_FIN_EXP,
ISNULL(EXC.PUESTO, '') AS PUESTO, ISNULL(EXC.DESCRIPCION, '') AS
DESCRIPCION,
ISNULL(ESEST.COD_ESP, '') AS COD_ESP_EST,
ISNULL(ESEST.COD_ANYOS_EXP, 0) AS COD_ANYOS_ESPEST,
ISNULL(ESEXP.COD_ESP, '')
AS COD_ESP_EXP, ISNULL(ESEXP.COD_ANYOS_EXP, 0)
AS COD_ANYOS_ESPEXP, ISNULL(I.COD_IDIOMA, '') AS COD_IDIOMA,
ISNULL(I.LEIDO, '0')
AS LEIDO, ISNULL(I.HABLADO, '0') AS HABLADO,
ISNULL(I.ESCRITO, '0') AS ESCRITO, ISNULL(I.TITULO, '') AS TITULO
FROM dbo.SQL_CANDIDATOS AS C LEFT OUTER JOIN
dbo.SQL_PROVINCIAS AS P ON C.COD_PROVINCIA >>> P.COD_PROVINCIA LEFT OUTER JOIN
dbo.SQL_ESTUDIOS_CAND AS EC ON C.NIF = EC.NIF
LEFT OUTER JOIN
dbo.SQL_TITULACIONES AS T ON EC.COD_TITULACION >>> T.COD_TITULACION LEFT OUTER JOIN
dbo.SQL_EXPERIENCIA_CAND AS EXC ON C.NIF >>> EXC.NIF LEFT OUTER JOIN
dbo.SQL_ESP_EST_CAND AS ESEST ON C.NIF >>> ESEST.NIF LEFT OUTER JOIN
dbo.SQL_ESP_EXP_CAND AS ESEXP ON C.NIF >>> ESEXP.NIF LEFT OUTER JOIN
dbo.SQL_IDIOMAS_CAND AS I ON C.NIF = I.NIF

Todas las tablas con las que hago el join son tablas de relación de
los candidatos con otras tablas.

El resultado es el esperado... a medias, puesto que si por ejemplo un
candidato tiene varias ocurrencias en SQL_ESTUDIOS_CANS y varias en
SQL_EXPERIENCIA muestra la combinación cartesiana de ambos. Viendo la
cantidad de tablas con las que se relacionan y previendo que cada uno
de los candidatos tenga varios registros relacionados en cada tabla,
la vista podría devolver una cantidad considerable de registros. Busco
otra forma de construir la consulta o alguna alternativa para realizar
el filtrado.

Saludos

On 3 mayo, 16:05, "Maxi" wrote:
Hola, la verdad que no sabemos, y no lo sabemos porque no sabemos que
has
hecho, para poderte ayudar debes mostrarnos que hicistes amigo, es
importante que nos envies:

1) DDL de tablas
2) query
3) Resultados esperados


Salu2

Microsoft MVP SQL Server
Culminis Speaker

"Juan Diego Bueno" escribió en el
mensajenews:
Hola gente:

Estoy desarrollando actualmente un proyecto en C# 2.0 + SQL Server
2005. El sistema de filtrado que he implementado se basa en una vista
obtenida a partir de una tabla principal (candidatos) y varias
relacionadas con Left outer join.

El tema es que la vista devuelve varias veces el mismo candidato (como
cabría de esperar) en función de las ocurrencias en cada una de las
tablas de relación y con combinación cartesiana, de tal forma que si
por un casual tiene n registros en una, m en otro y así
sucesivamente, puede aparecer n x m x ... veces el mismo candidato, lo
cual cuando la base de datos se cubra con una cantidad considerable de
candidatos y sus datos relacionados, puede dar una vista que devuelva
muchísimos registros.

¿Alguna forma de poder realizar esta consulta de manera que devuelva
los menos registros posibles?. O en su defecto alguna alternativa
eficaz a este sistema.

Gracias de antemano

Saludos













Respuesta Responder a este mensaje
#9 Jesús López
04/05/2007 - 12:31 | Informe spam
No me parece una buena idea hacer alter views para ejecutar consultas, las
vistas en una base de datos no deberían cambiar cada vez que se hace una
consulta, esto trae problemas de concurrencia, el usuario tiene que tener
más permisos. Una vista debería ser más o menos permanente. Para eso sería
mejor construir la instrucción SQL en la aplicación cliente y punto.

Una solución es crear un procedimiento almacenado que sirva para buscar los
candidatos sea cual sea la condición que ha elegido el usuario, el
procedimiento puede hacer uso de ejecución dinámica.

Por ejemplo, supongamos que tenemos las tablas:

CREATE TABLE Candidatos
(
IdCandidato int IDENTITY(1,1) PRIMARY KEY,
NIF varchar(50) UNIQUE,
Nombre varchar(50) NOT NULL
)
go
CREATE TABLE Titulaciones
(
IdTitulacion int IDENTITY(1,1) PRIMARY KEY,
Titulacion varchar(50) NOT NULL,
)
go
CREATE TABLE TitulacionesCandidatos
(
IdCandidato int NOT NULL,
IdTitulacion int NOT NULL,
PRIMARY KEY(IdCandidato, IdTitulacion)
)


Queremos un procedimiento que busque los candidatos por NIF, Nombre, o que
tenga alguna de las Titulaciones indicadas o cualquier combinación de ellas
combinadas con AND. Como Titulaciones pueden ser varias no lo podemos
pasar en una varaible, necesitaríamos un array, pero no hay arrays en SQL.
Lo que sí tenemos es XML que también nos puede servir

Podríamos usar un procedimiento como este:

CREATE PROCEDURE BuscarCandidato
@Nif varchar(50),
@Nombre varchar(50),
@Titulaciones xml
AS
DECLARE @sql nvarchar(max)
SET @sql N'SELECT IdCandidato, Nif, Nombre
FROM Candidatos
WHERE 1=1'

IF @Nif IS NOT NULL
SET @sql = @sql + N' AND Nif = @Nif'
IF @Nombre IS NOT NULL
SET @sql = @sql + ' AND Nombre = @Nombre'
IF @Titulaciones IS NOT NULL
SET @sql = @sql + N' AND IdCandidato IN
(SELECT IdCandidato
FROM TitulacionesCandidatos
WHERE IdTitulacion IN (SELECT
Id.value(''.'',''int'')
FROM @Titulaciones.nodes(''//Id'') AS
Titulaciones(Id)))'

exec sp_executesql @sql, N'@Nif varchar(50), @Nombre varchar(50),
@Titulaciones xml', @Nif, @Nombre, @Titulaciones
GO

Por ejemplo para buscar los candidatos que tengan la titulación 1 o la
titulación 2 sería:

exec BuscarCandidato NULL, NULL,
N'<Titulaciones><Id>1</Id><Id>2</Id></Titulaciones>'

Saludos:

Jesús López







"Juan Diego Bueno" escribió en el mensaje
news:

On 4 mayo, 11:01, "Jesús López" wrote:
Yo rediseñaría el formulario, pondría en la parte izquierda un grid que
muestre la lista de candidatos con sus campos más significativos y en la
parte derecha toda la información relativa al candidato que el usuario
haya
seleccionado en el grid. En la parte derecha puedes tener varios grids e
incluso fichas (tabs) que el usuario pueda seleccionar para ver la
información. Cuando el el usuario selecciona un candidato entonces
ejecutas
una consulta parametrizada por el NIF o Id del candidato seleccionado o un
procedimiento almacenado que obtiene la información relativa a ese
candidato.



Es que el objetivo del formulario es un filtrado general sobre los
candidatos y sus tablas relacionadas. La idea es hacer un AND sobre
los campos que el usuario seleccione y en los casos en los que
proceda, permitir un OR con ocurrencias del mismo campo.


Lo de crear campos con múltiples valores por medio de la concatenación es
una buena solución siempre que no sean muchos los valores a concatenar. La
pega es la concatenación es difícil de implementar y poco eficiente (uso
de
cursores) en SQL 2000, en SQL 2005 es más sencillo y eficiente, usando
funciones de agregado creadas con CLR o trucos con XML. ¿qué versión
usas?.



Uso SQL 2005

Te cuento lo que he hecho al final, que creo es la solución más
eficiente que se me ha ocurrido.

Creo una vista sobre la tabla principal parametrizando los campos que
no van a permitir más de una ocurrencia (filtrado por nif o por nombre
del candidato)

Creo una vista para cada una de las tablas relacionadas

Ahora supongamos que el usuario ha elegido para el filtrado, dos
titulaciones y tres puestos de trabajo de experiencia, las cuales
están en diferentes tablas de relación. Mediante un sqlcommand, hago
un alter view de la vista de titulaciones añadiendo el filtro que
previamente he generado (ya que aquí no puedo usar parámetros al tener
un cod_titulacion='tit1' or cod_titulacion='tit2'), tres cuartos de lo
mismo con la de la experiencia (espero se me haya entendido)

Ahora hago un alter view de la vista anterior añadiendo dos inner
join, uno por cada una de esas vistas relacionadas

Todavía no lo he acabado de implementar, pero debería funcionar. De
esta forma, sólo genero las vistas que necesite y las uso en la
consulta. Si no necesitara filtrado de ninguna de las tablas
relacionadas, la vista principal quedaría solo con los campos
parametrizados inicialmente.

Tu dirás si es buena opción o no

Saludos
Respuesta Responder a este mensaje
#10 Jesús López
04/05/2007 - 13:11 | Informe spam
Por cierto, el usario prodría pedir tanto que tenga alguna de las
titulaciones especificadas como que tenga todas las titulaciones
especificadas.

El procedimiento entonces quedaría así:

ALTER PROCEDURE BuscarCandidato
@Nif varchar(50),
@Nombre varchar(50),
@Titulaciones xml,
@CondicionTitulaciones varchar(50)
AS
DECLARE @sql nvarchar(max)
SET @sql N'SELECT IdCandidato, Nif, Nombre
FROM Candidatos
WHERE 1=1'

IF @Nif IS NOT NULL
SET @sql = @sql + N' AND Nif = @Nif'
IF @Nombre IS NOT NULL
SET @sql = @sql + ' AND Nombre = @Nombre'
IF @Titulaciones IS NOT NULL
BEGIN
IF @CondicionTitulaciones = 'Alguna'
SET @sql = @sql + N' AND IdCandidato IN
(SELECT IdCandidato
FROM TitulacionesCandidatos
WHERE IdTitulacion IN (SELECT Id.value(''.'',''int'')
FROM @Titulaciones.nodes(''//Id'') AS Titulaciones(Id)))'
ELSE
SET @sql = @sql + N' AND NOT EXISTS
(SELECT *
FROM @Titulaciones.nodes(''//Id'') AS Titulaciones(Id)
WHERE Id.value(''.'',''int'') NOT IN (SELECT IdTitulacion
FROM
TitulacionesCandidatos
WHERE IdCandidato =
Candidatos.IdCandidato))'
END
exec sp_executesql @sql, N'@Nif varchar(50), @Nombre varchar(50),
@Titulaciones xml', @Nif, @Nombre, @Titulaciones
GO

Y usarlo así:

DECLARE @Titulaciones xml
SET @Titulaciones = N'<Titulaciones><Id>1</Id><Id>2</Id></Titulaciones>'
exec BuscarCandidato NULL, NULL,
N'<Titulaciones><Id>1</Id><Id>2</Id></Titulaciones>', 'Todas'


Saludos:

Jesús López
www.solidqualitylearning.com



"Jesús López" escribió en el mensaje
news:
No me parece una buena idea hacer alter views para ejecutar consultas, las
vistas en una base de datos no deberían cambiar cada vez que se hace una
consulta, esto trae problemas de concurrencia, el usuario tiene que tener
más permisos. Una vista debería ser más o menos permanente. Para eso sería
mejor construir la instrucción SQL en la aplicación cliente y punto.

Una solución es crear un procedimiento almacenado que sirva para buscar
los candidatos sea cual sea la condición que ha elegido el usuario, el
procedimiento puede hacer uso de ejecución dinámica.

Por ejemplo, supongamos que tenemos las tablas:

CREATE TABLE Candidatos
(
IdCandidato int IDENTITY(1,1) PRIMARY KEY,
NIF varchar(50) UNIQUE,
Nombre varchar(50) NOT NULL
)
go
CREATE TABLE Titulaciones
(
IdTitulacion int IDENTITY(1,1) PRIMARY KEY,
Titulacion varchar(50) NOT NULL,
)
go
CREATE TABLE TitulacionesCandidatos
(
IdCandidato int NOT NULL,
IdTitulacion int NOT NULL,
PRIMARY KEY(IdCandidato, IdTitulacion)
)


Queremos un procedimiento que busque los candidatos por NIF, Nombre, o que
tenga alguna de las Titulaciones indicadas o cualquier combinación de
ellas combinadas con AND. Como Titulaciones pueden ser varias no lo
podemos pasar en una varaible, necesitaríamos un array, pero no hay arrays
en SQL. Lo que sí tenemos es XML que también nos puede servir

Podríamos usar un procedimiento como este:

CREATE PROCEDURE BuscarCandidato
@Nif varchar(50),
@Nombre varchar(50),
@Titulaciones xml
AS
DECLARE @sql nvarchar(max)
SET @sql > N'SELECT IdCandidato, Nif, Nombre
FROM Candidatos
WHERE 1=1'

IF @Nif IS NOT NULL
SET @sql = @sql + N' AND Nif = @Nif'
IF @Nombre IS NOT NULL
SET @sql = @sql + ' AND Nombre = @Nombre'
IF @Titulaciones IS NOT NULL
SET @sql = @sql + N' AND IdCandidato IN
(SELECT IdCandidato
FROM TitulacionesCandidatos
WHERE IdTitulacion IN (SELECT
Id.value(''.'',''int'')
FROM @Titulaciones.nodes(''//Id'') AS
Titulaciones(Id)))'

exec sp_executesql @sql, N'@Nif varchar(50), @Nombre varchar(50),
@Titulaciones xml', @Nif, @Nombre, @Titulaciones
GO

Por ejemplo para buscar los candidatos que tengan la titulación 1 o la
titulación 2 sería:

exec BuscarCandidato NULL, NULL,
N'<Titulaciones><Id>1</Id><Id>2</Id></Titulaciones>'

Saludos:

Jesús López







"Juan Diego Bueno" escribió en el mensaje
news:

On 4 mayo, 11:01, "Jesús López" wrote:
Yo rediseñaría el formulario, pondría en la parte izquierda un grid que
muestre la lista de candidatos con sus campos más significativos y en la
parte derecha toda la información relativa al candidato que el usuario
haya
seleccionado en el grid. En la parte derecha puedes tener varios grids e
incluso fichas (tabs) que el usuario pueda seleccionar para ver la
información. Cuando el el usuario selecciona un candidato entonces
ejecutas
una consulta parametrizada por el NIF o Id del candidato seleccionado o
un
procedimiento almacenado que obtiene la información relativa a ese
candidato.



Es que el objetivo del formulario es un filtrado general sobre los
candidatos y sus tablas relacionadas. La idea es hacer un AND sobre
los campos que el usuario seleccione y en los casos en los que
proceda, permitir un OR con ocurrencias del mismo campo.


Lo de crear campos con múltiples valores por medio de la concatenación
es
una buena solución siempre que no sean muchos los valores a concatenar.
La
pega es la concatenación es difícil de implementar y poco eficiente (uso
de
cursores) en SQL 2000, en SQL 2005 es más sencillo y eficiente, usando
funciones de agregado creadas con CLR o trucos con XML. ¿qué versión
usas?.



Uso SQL 2005

Te cuento lo que he hecho al final, que creo es la solución más
eficiente que se me ha ocurrido.

Creo una vista sobre la tabla principal parametrizando los campos que
no van a permitir más de una ocurrencia (filtrado por nif o por nombre
del candidato)

Creo una vista para cada una de las tablas relacionadas

Ahora supongamos que el usuario ha elegido para el filtrado, dos
titulaciones y tres puestos de trabajo de experiencia, las cuales
están en diferentes tablas de relación. Mediante un sqlcommand, hago
un alter view de la vista de titulaciones añadiendo el filtro que
previamente he generado (ya que aquí no puedo usar parámetros al tener
un cod_titulacion='tit1' or cod_titulacion='tit2'), tres cuartos de lo
mismo con la de la experiencia (espero se me haya entendido)

Ahora hago un alter view de la vista anterior añadiendo dos inner
join, uno por cada una de esas vistas relacionadas

Todavía no lo he acabado de implementar, pero debería funcionar. De
esta forma, sólo genero las vistas que necesite y las uso en la
consulta. Si no necesitara filtrado de ninguna de las tablas
relacionadas, la vista principal quedaría solo con los campos
parametrizados inicialmente.

Tu dirás si es buena opción o no

Saludos



Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida