T-SQL. SELECT con LIKE un tanto extraña

19/10/2007 - 22:59 por Pablo Roca | Informe spam
Disculpas por el titulo de este mensaje, pero la verdad que no sabia como
titularlo.

Tengo una tabla (un menú) de esta manera:

CREATE TABLE [dbo].[x_menu](
[pk_x_menu_id] [smallint] IDENTITY(1,1) NOT NULL,
[mnumodulo] [char](3) NOT NULL,
[mnugrupo] [char](10) NOT NULL,
[mnutal] [char](2) NOT NULL,
[mnucodigo] [char](6) NOT NULL,
[mnutexto] [char](40) NOT NULL,
[mnutecla] [char](1) NOT NULL,
[mnunivel] [decimal](2, 0) NOT NULL,
[mnuclave] [char](8) NOT NULL,
[mnuclavev] [bit] NOT NULL,
[mnuprg] [char](12) NOT NULL,
[mnufin] [bit] NOT NULL,
[mnuparam] [char](40) NOT NULL,
CONSTRAINT [pk_x_menu_id] PRIMARY KEY CLUSTERED

Lo importante es:

En mnumodulo se guarda a que modulo pertenece el menu
En mnunivel se guarda el nivel de acceso (puede ser un numero entre 0 menor
nivel y 99 mayor nivel)

Quiero saber los registros que cumplan esta condicion:

Para un usuario determinado tengo un string que me indica los modulos y el
nivel de acceso de cada modulo de la siguiente manera:

modulo,nivel;...

ejemplo:

GES,20;TES,99;CON,50;PRO,99;COS,99;HEX,99;PER,99;FRI,99;

Sacar los modulos de un usuario lo puedo hacer facilmente con un
procedimiento almacenado de esta manera:


USE [GRECCO_BASE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[x_menu_leer]
@modulo varchar(70)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM x_menu WHERE @modulo LIKE '%'+mnumodulo+',%'
END

La Select es un tanto peculiar, ya que estoy acostombrado a poner los LIKE
al reves, pero funciona.

¿pero como podria hacer para sacar los registros considerando el nivel de
usuario por cada modulo, fijaros que el ejemplo tengo

GES,20;TES,99;CON,50;

Entonces quiero que me devuelva los registros con estas condiciones:

GES nivel 20
TES nivel 99
CON nivel 50

La verdad que estoy empezando seriamente a considerar en cambiar mi tabla de
usuarios y hacerme una tabla nueva de usuarios con modulos-niveles para que
sea mas facil esta consulta.

Bueno .. ¿Alguna idea?



Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com

Preguntas similare

Leer las respuestas

#1 Gux (MVP)
19/10/2007 - 23:15 | Informe spam
No me gusta la implementación de poner un string con la forma:

GES,20;TES,99;CON,50;PRO,99;COS,99;HEX,99;PER,99;FRI,99;

porque no cumple siquiera con la Primera Forma Normal. No es que sea muy
malo no cumplir 1NF, pero en la práctica implica demasiadas operaciones de
manipulación y consultas muy ineficientes pues los índices no sirven
demasiado con ese tipo de desnormalizaciones.

Si aún hay tiempo de rediseñar, ver de normalizar esa info.

Gustavo Larriera, Microsoft MVP
https://mvp.support.microsoft.com/profile/gux
Este mensaje se proporciona tal como es, sin garantías de ninguna clase.



"Pablo Roca" wrote:

Disculpas por el titulo de este mensaje, pero la verdad que no sabia como
titularlo.

Tengo una tabla (un menú) de esta manera:

CREATE TABLE [dbo].[x_menu](
[pk_x_menu_id] [smallint] IDENTITY(1,1) NOT NULL,
[mnumodulo] [char](3) NOT NULL,
[mnugrupo] [char](10) NOT NULL,
[mnutal] [char](2) NOT NULL,
[mnucodigo] [char](6) NOT NULL,
[mnutexto] [char](40) NOT NULL,
[mnutecla] [char](1) NOT NULL,
[mnunivel] [decimal](2, 0) NOT NULL,
[mnuclave] [char](8) NOT NULL,
[mnuclavev] [bit] NOT NULL,
[mnuprg] [char](12) NOT NULL,
[mnufin] [bit] NOT NULL,
[mnuparam] [char](40) NOT NULL,
CONSTRAINT [pk_x_menu_id] PRIMARY KEY CLUSTERED

Lo importante es:

En mnumodulo se guarda a que modulo pertenece el menu
En mnunivel se guarda el nivel de acceso (puede ser un numero entre 0 menor
nivel y 99 mayor nivel)

Quiero saber los registros que cumplan esta condicion:

Para un usuario determinado tengo un string que me indica los modulos y el
nivel de acceso de cada modulo de la siguiente manera:

modulo,nivel;...

ejemplo:

GES,20;TES,99;CON,50;PRO,99;COS,99;HEX,99;PER,99;FRI,99;

Sacar los modulos de un usuario lo puedo hacer facilmente con un
procedimiento almacenado de esta manera:


USE [GRECCO_BASE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[x_menu_leer]
@modulo varchar(70)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM x_menu WHERE @modulo LIKE '%'+mnumodulo+',%'
END

La Select es un tanto peculiar, ya que estoy acostombrado a poner los LIKE
al reves, pero funciona.

¿pero como podria hacer para sacar los registros considerando el nivel de
usuario por cada modulo, fijaros que el ejemplo tengo

GES,20;TES,99;CON,50;

Entonces quiero que me devuelva los registros con estas condiciones:

GES nivel 20
TES nivel 99
CON nivel 50

La verdad que estoy empezando seriamente a considerar en cambiar mi tabla de
usuarios y hacerme una tabla nueva de usuarios con modulos-niveles para que
sea mas facil esta consulta.

Bueno .. ¿Alguna idea?



Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com



Respuesta Responder a este mensaje
#2 Alejandro Mesa
20/10/2007 - 03:25 | Informe spam
Hola Pablo,

Comparto la opinion de Gustavo. Si estas a tiempo, entonces debes normalizar
esa tabla.

Otra opcion seria crearte una funcion que devuelva una tabla, partiendo del
valor de la lista. En SS 2005 tambien puedes usar el operador CROSS APPLY
para optener la relacion de cada usuario con el resultado de la funcion.

Ejemplo:

CREATE FUNCTION dbo.ufn_Numbers (
@Number INT
)
RETURNS TABLE
AS
RETURN (
WITH
L0 AS (SELECT 1 AS c1 UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c1 FROM L0 AS a CROSS JOIN L0 AS b),
L2 AS (SELECT 1 AS c1 FROM L1 AS a CROSS JOIN L1 AS b),
L3 AS (SELECT 1 AS c1 FROM L2 AS a CROSS JOIN L2 AS b),
L4 AS (SELECT 1 AS c1 FROM L3 AS a CROSS JOIN L3 AS b),
Numbers AS (SELECT ROW_NUMBER() OVER(ORDER BY c1) AS Number FROM L4)
SELECT Number
FROM Numbers
WHERE Number <= @Number
)
GO

CREATE FUNCTION dbo.ufn_Split (
@p VARCHAR(256),
@c CHAR(1) = ';'
)
RETURNS @t TABLE ([Value] VARCHAR(256))
AS
BEGIN

INSERT INTO @t ([Value])
SELECT
SUBSTRING(@c + @p + @c, Number + 1, CHARINDEX( @c, @c + @p + @c, Number +
1) - Number - 1)
FROM
dbo.ufn_Numbers(LEN(@c + @p + @c))
WHERE
SUBSTRING(@c + @p + @c, Number, 1 ) = @c AND Number < LEN( @c + @p + @c)

RETURN
END
GO

CREATE TABLE dbo.Usuario (
usuario_id INT NOT NULL IDENTITY PRIMARY KEY,
modulo_nivel VARCHAR(256)
)
GO

INSERT INTO dbo.Usuario (modulo_nivel) VALUES
('GES,20;TES,99;CON,50;PRO,99;COS,99;HEX,99;PER,99;FRI,99;')
GO

SELECT
u.[usuario_id],
s.[Value],
PARSENAME(REPLACE(s.[Value], ',', '.'), 2) AS modulo,
PARSENAME(REPLACE(s.[Value], ',', '.'), 1) AS nivel
FROM
dbo.Usuario AS u
CROSS APPLY
dbo.ufn_Split(LEFT(u.modulo_nivel, LEN(u.modulo_nivel) - 1), DEFAULT) AS s
GO

DROP FUNCTION ufn_Split
GO

DROP FUNCTION dbo.ufn_Numbers
GO

GO


AMB



"Pablo Roca" wrote:

Disculpas por el titulo de este mensaje, pero la verdad que no sabia como
titularlo.

Tengo una tabla (un menú) de esta manera:

CREATE TABLE [dbo].[x_menu](
[pk_x_menu_id] [smallint] IDENTITY(1,1) NOT NULL,
[mnumodulo] [char](3) NOT NULL,
[mnugrupo] [char](10) NOT NULL,
[mnutal] [char](2) NOT NULL,
[mnucodigo] [char](6) NOT NULL,
[mnutexto] [char](40) NOT NULL,
[mnutecla] [char](1) NOT NULL,
[mnunivel] [decimal](2, 0) NOT NULL,
[mnuclave] [char](8) NOT NULL,
[mnuclavev] [bit] NOT NULL,
[mnuprg] [char](12) NOT NULL,
[mnufin] [bit] NOT NULL,
[mnuparam] [char](40) NOT NULL,
CONSTRAINT [pk_x_menu_id] PRIMARY KEY CLUSTERED

Lo importante es:

En mnumodulo se guarda a que modulo pertenece el menu
En mnunivel se guarda el nivel de acceso (puede ser un numero entre 0 menor
nivel y 99 mayor nivel)

Quiero saber los registros que cumplan esta condicion:

Para un usuario determinado tengo un string que me indica los modulos y el
nivel de acceso de cada modulo de la siguiente manera:

modulo,nivel;...

ejemplo:

GES,20;TES,99;CON,50;PRO,99;COS,99;HEX,99;PER,99;FRI,99;

Sacar los modulos de un usuario lo puedo hacer facilmente con un
procedimiento almacenado de esta manera:


USE [GRECCO_BASE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[x_menu_leer]
@modulo varchar(70)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM x_menu WHERE @modulo LIKE '%'+mnumodulo+',%'
END

La Select es un tanto peculiar, ya que estoy acostombrado a poner los LIKE
al reves, pero funciona.

¿pero como podria hacer para sacar los registros considerando el nivel de
usuario por cada modulo, fijaros que el ejemplo tengo

GES,20;TES,99;CON,50;

Entonces quiero que me devuelva los registros con estas condiciones:

GES nivel 20
TES nivel 99
CON nivel 50

La verdad que estoy empezando seriamente a considerar en cambiar mi tabla de
usuarios y hacerme una tabla nueva de usuarios con modulos-niveles para que
sea mas facil esta consulta.

Bueno .. ¿Alguna idea?



Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com



Respuesta Responder a este mensaje
#3 Pablo Roca
20/10/2007 - 11:05 | Informe spam
Hola Gustavo,

Pues tiempo no hay mucho .. pero la verdad que tal y como tengo los datos...
este cambio merece la pena.

La verdad que nunca me gustó ese diseño. Gracias


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
Respuesta Responder a este mensaje
#4 Pablo Roca
20/10/2007 - 11:06 | Informe spam
Gracias Alejendro,

Si, creo que voy a cambiarlo, porque tal y como está es un infierno. Vamos a
hacerlo bien.


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
Respuesta Responder a este mensaje
#5 Pablo Roca
23/10/2007 - 11:46 | Informe spam
Ok, gracias a los .. creada una nueva tabla de usuarios y permisos por
modulos.

Ahora el Select me quedó fácil:

SELECT mnucodigo ,mnutexto ,mnutecla ,mnunivel ,mnuclave
,mnuclavev ,mnuprg ,mnufin ,mnuparam
FROM [GRECCO_BASE].[dbo].[x_menu]
INNER JOIN rolmodulos ON x_menu.pk_modcod = rolmodulos.pk_modcod AND
x_menu.mnunivel <= rolmodulos.rmonivel
WHERE pk_usucod = @usuario AND mnugrupo LIKE '%'+@grupomenu+'%' AND
(mnutal = @tipoalma OR mnutal = '')
ORDER BY mnucodigo



Saludos,

Pablo Roca
La Coruna - Spain
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida