CONTENCIÓN DE CONSULTAS CON VALORES NULOS USANDO EL MÉTODO CQC Guillem Rull1, Carles Farré1 y Toni Urpí1 1: Departamento de Lenguajes y Sistemas Informáticos Universitat Politècnica de Catalunya 08034 Barcelona, España e-mail: {grull, farre, urpi}@lsi.upc.edu Palabras clave: Validación de esquemas de bases de datos, Contención de consultas, Tratamiento de restricciones, Valores nulos Resumen. Este artículo presenta una extensión de nuestro método CQC destinada a comprobar la contención de dos consultas en el contexto de una BD relacional que puede contener valores nulos en los atributos de sus tuplas. Teniendo en cuenta que todos los SGBDs admiten el uso de valores nulos y que las bases de datos “reales” contienen valores nulos, comprobar la contención de consultas en este contexto es una cuestión muy importante de cara a la aplicación practica. Al igual que el método original, esta extensión permite tratar con restricciones de integridad, negaciones en predicados EDB e IDB, y predicados built-in. Además de para comprobar la contención de consultas, se puede aplicar el método y esta extensión a la validación de esquemas de BD relacionales con valores nulos. 1. INTRODUCCIÓN La contención de consultas es uno de los problemas más importantes en el campo de las bases de datos. Se utiliza como técnica de base en muchos contextos: optimización de consultas [2, 11], reescritura de consultas usando vistas [6], detectar la independencia de consultas respecto a actualizaciones en la base de datos [9], comprobación de restricciones [5], etc. A grandes rasgos, se dice que una consulta está contenida en otra cuando el conjunto de tuplas que se obtiene como respuesta de la primera es un subconjunto del conjunto de tuplas que se obtiene como respuesta de la segunda, para todos los estados de la base de datos. El problema se ha estudiado para la clase de las consultas conjuntivas [2], conjuntivas con comparaciones de orden [9], unión de consultas conjuntivas [11], consultas con átomos extensionales negados safe [9], y también considerando restricciones de integridad [8]. Para trasladar estos resultados a la practica, sobre BD reales, es imprescindible tratar dos cuestiones: la semántica de bolsas y los valores nulos. La semántica de bolsas es necesaria dado que SQL permite que aparezcan duplicados en las respuestas de las consultas (a menos que se utilice DISTINCT). La contención de consultas para consultas conjuntivas con semántica de bolsas se ha tratado en [7, 1]. El caso de la contención de consultas con posible presencia de valores nulos en los atributos de las tuplas, según nuestro conocimiento, no ha sido tratado por nadie hasta el momento. Éste será el objetivo de este artículo. Teniendo en cuenta que todos los SGBDs admiten el uso de valores nulos y que las bases de datos “reales” contienen valores nulos, es obvio que ser capaces de comprobar la contención de consultas en este contexto es una cuestión muy importante de cara a la aplicación practica. Además, hay que tener también en cuenta que una misma relación de contención entre dos consultas puede tener lugar o no dependiendo de si se consideran o no valores nulos. Como ejemplo motivador, considérense las dos consultas siguientes: Q1: SELECT nombre FROM Empleados Q2: SELECT e.nombre FROM Empleados e, Categorias c WHERE e.nombreCat = c.nombre AND c.salario > 40000 Estas consultas están definidas sobre el siguiente esquema de base de datos: CREATE TABLE Categorias ( nombre char(10) PRIMARY KEY, salario real NOT NULL CHECK (salario > 50000) ) CREATE TABLE Empleados( nss int PRIMARY KEY, nombre char(30) NOT NULL, nombreCat char(10) references Categorias(nombre) ) En este ejemplo, si no se consideran valores nulos, ambas consultas son equivalentes. La consulta Q2 devuelve todos los empleados con un salario superior a 40000 que, debido a la restricción CHECK de la tabla Categorias, son todos los empleados. Así pues, ambas consultas devuelven todas las tuplas de la tabla Empleados. En cambio, si se permite que nombreCat pueda tener valores nulos, entonces Q1 no está contenida en Q2. Esto es debido a que para aquellas tuplas donde nombreCat es nulo, la comparación e.nombreCat = c.nombre se evalúa a “desconocido”. La cláusula WHERE, por tanto, seguro que no se evaluará a “cierto”. Debido a que una sentencia SELECT sólo devuelve aquellas tuplas para las cuales el WHERE se evalúa a “cierto”, la consulta Q2 no devolverá aquellas tuplas donde nombreCat tenga valor nulo. Así pues, dado que Q1 sí devuelve todas las tuplas de la tabla Empleados, el resultado es, ciertamente, que Q1 no está contenido en Q2. Para comprobar la contención de consultas con valores nulos, se ha extendido nuestro Constructive Query Containment (CQC) Method [4], un método que intenta demostrar que la contención no tiene lugar mediante la construcción de un contraejemplo. El método garantiza que si no es capaz de construir dicho contraejemplo, es que éste no existe, y por lo tanto, la contención de consultas sí tiene lugar. El método CQC es correcto y completo, permite comprobar la contención de consultas en presencia/ausencia de restricciones de integridad, tratar con negaciones tanto en predicados extensionales como intensionales, tratar con comparaciones de igualdad/desigualdad, así como con otras comparaciones (<, ≤, ≥, >) interpretadas ya sea en un dominio de orden discreto como en uno denso. Originalmente, el método no contempla la posibilidad de valores nulos. En el apartado 3 se explican las modificaciones necesarias para extender el método y que éste pueda trabajar con valores nulos. Además de para comprobar si una consulta está o no contenida en otra, el método CQC, así como su versión extendida con valores nulos, también puede aplicarse a la validación de esquemas de bases de datos [3, 12], es decir, que se puede utilizar para comprobar si un esquema satisface o no ciertas propiedades deseables. Ser capaces de realizar esta validación de esquemas con valores nulos es si cabe todavía más importante de cara a una utilización comercial, puesto que las empresas querrán poder validar los esquemas de sus bases de datos los cuales contendrán sin duda valores nulos. La validación de esquemas con valores nulos se comenta en el apartado 4. 2. PRELIMINARES El método CQC trabaja sobre una representación de la base de datos en lógica de primer orden. A lo largo del artículo usaremos la notación presentada en [13]. A continuación se repasan tan solo algunos conceptos básicos. Una regla de deducción es de la forma: p(X̄) ← r1(X̄1) ∧ … ∧ rn(X̄n) ∧ ¬rn+1(Ȳ1) ∧ … ∧ ¬rm(Ȳs) ∧ C1 ∧… ∧ Ct Una restricción (o condición) es de la forma: ← r1(X̄1) ∧ … ∧ rn(X̄n) ∧ ¬rn+1(Ȳ1) ∧ … ∧ ¬rm(Ȳs) ∧ C1 ∧… ∧ Ct En ambos casos, p y r1, …, rm son predicados (también llamados relaciones). Cada Ci es un literal built-in A1 θ A2, donde A1 y A2 son términos y θ puede ser <, ≤, >, ≥, = o ≠. La evaluación de las reglas y de las restricciones se ve afectada por la presencia de valores nulos. Esto implica la necesidad de considerar una lógica trivalor, que define tres valores de verdad: “cierto”, “falso” y “desconocido”. Esta lógica se aplica fundamentalmente en la evaluación de los predicados built-in, así como en la evaluación de los cuerpos de reglas y restricciones. Cuando se tiene una comparación en donde alguno de los términos es la constante null, el predicado built-in en cuestión se evalúa a “desconocido”. Cuando en una regla o en una restricción uno de los literales se evalúa a “desconocido”, su cuerpo (una conjunción de literales) ya es seguro que no será cierto; se evaluará a “desconocido” si todos los demás literales son ciertos, o a “falso” si alguno de los otros literales es falso. Cómo actúa exactamente el método CQC en esta situación, se ve en el siguiente apartado. 3. EL MÉTODO CQC Recordemos que el método CQC comprueba la contención de dos consultas mediante la construcción de un contraejemplo, una EDB, que de existir demuestra que la contención no se produce, y de no existir que sí se produce. La EDB que se construye como contraejemplo tiene que satisfacer las restricciones de integridad y además satisfacer la propiedad de que no tenga lugar la contención de las consultas. Éstas son precisamente las dos “entradas” básicas del método CQC: las conditions to enforce y el goal to attain, respectivamente. Las conditions to enforce son el conjunto de condiciones correspondientes a la traducción a lógica de las restricciones de integridad. El goal to attain es una condición que la EDB contraejemplo tiene que satisfacer y que, para comprobar la contención de consultas, suele ser de la forma ← q1(X̄) ∧ ¬q2(X̄). Para entender cómo la presencia de valores nulos afecta tanto al goal como a las conditions to enforce, hay que ver cuál es la semántica que el SQL estándar define para los valores nulos. En el caso de una restricción de integridad tipo CHECK, una tupla viola la restricción solamente si la condición del CHECK se evalúa a “falso”; por tanto, si al haber valores nulos ésta se evalúa a “desconocido”, la restricción no se viola. En el caso de una sentencia SELECT, sólo devuelve como resultado aquellas tuplas para las cuales la cláusula WHERE se evalúa a “cierto”; por tanto, si debido a la presencia de valores nulos en una tupla, el WHERE se evalúa a “desconocido”, esta tupla no forma parte del resultado del SELECT. Este mismo razonamiento se puede aplicar al goal y a las conditions to enforce. En el caso del goal, la EDB construida tiene que evaluarlo a “cierto”; por tanto, si se evalúa a “desconocido” es lo mismo que si se evaluara a “falso”. En el caso de la conditions to enforce, en cambio, si alguna de ellas se evalúa a “cierto”, la restricción se viola; por tanto, si se evalúa a “desconocido”, la restricción no se violará, siendo equivalente a si se evaluara a “falso”. La conclusión que se extrae es que en caso de que un literal built-in, ya sea del goal o de una restricción, se evalúe a “desconocido”, el método CQC tiene que actuar tal y como lo haría en caso de que se hubiera evaluado a “falso”. A continuación se hace un breve resumen del método CQC original, y luego, una explicación más detallada de los cambios exactos que hay que hacer al método para que pueda tratar con valores nulos. 3.1. Resumen del método El funcionamiento del método CQC consta, básicamente, de dos tareas que se van alternando. Por un lado, se van añadiendo hechos a la EDB en construcción (inicialmente vacía) con el objetivo de llegar a satisfacer el goal to attain, y por otro, se va comprobando que dicha EDB no viola las restricciones de integridad. Las restricciones pendientes de ser comprobadas son las conditions to enforce. Las restricciones que ya se han comprobado y que deben mantenerse en el futuro, volviéndolas a comprobar cuando se añade un nuevo hecho a la EDB, se denominan conditions to maintain. Para cada una de estas dos tareas, el método selecciona un literal, del goal o de una de las conditions to enforce, según el caso; y luego, si es posible, aplica una regla de expansión. Las reglas de expansión provocan como un cambio de estado del método. El método CQC puede verse, pues, como la exploración de un árbol de estados. Cada estado, o nodo CQC, es una tupla de la forma (Gi, Fi, Ti, Ci, Ki) donde Gi es el goal to attain, Fi las conditions to enforce, Ti la EDB en construcción, Ci las conditions to maintain, y Ki el conjunto de constantes utilizadas en R = DR ∪ Q1 ∪ Q2 ∪ IC y en Ti. Cada una de las ramas del árbol CQC es lo que se denomina una derivación CQC. Cuando el método falla, garantiza que no existe ningún contraejemplo. Esto es posible gracias al uso de los VIPs (Variable Instantiation Patterns), que garantizan que para cada variable se prueban todas las constantes significativas. El método CQC define cuatro VIPs: Simple VIP, Negation VIP, Dense Order VIP y Discrete Order VIP. La explicación detallada del método CQC original, así como su formalización, se puede consultar en [4]. En el apartado 3.3 se muestra un ejemplo de aplicación del método. 3.2. Modificaciones para tratar con valores nulos Como se ha visto, originariamente el método CQC no contempla la posibilidad de que puedan haber tuplas donde alguno de sus atributos tenga valor nulo. A continuación se detallan los cambios concretos que son necesarios aplicar para que pueda tratar con estos valores nulos. Teniendo en cuenta que los VIPs controlan la asignación de constantes a las variables, es lógico que sean el punto de partida de los cambios a realizar. Para los cuatro VIPs el cambio a realizar es básicamente el mismo; hay que añadir una nueva regla al conjunto de reglas de cada VIP, que asigne la constante null a la variable que se esté considerando. Más formalmente, a cada VIP hay que añadir la siguiente regla: X̄i+1 = X̄i \ Xi+1, θi+1 = θi ∪ {Xi+1 / null} y Ki+1 = Ki. donde Xi+1 es la variable a la que se asigna la constante y θi+1 la sustitución que se construye. Además de los VIPs, hay que modificar también las reglas de expansión. De estas reglas, se ven afectadas las que tratan con las comparaciones, es decir, los literales built-in. Como ya se ha explicado, en caso de encontrar-se con un literal built-in que se evalúe a “desconocido” debido a que uno de sus términos es la constante null, el método tiene que actuar tal y como lo haría en caso de que el literal se evaluara a “falso”. Este hecho se refleja en las reglas A4, B4 y B5, que quedan de la forma siguiente: (A4) P(Gi) = L es un literal built-in de términos constantes: (Gi Fi Ti Ci Ki) (Gi \ L Fi Ti Ci Ki) sólo si L se evalúa a “cierto” según la lógica trivalor. (B4) P(Fi,j) = L es un literal built-in de términos constantes que se evalúa a “cierto” según la lógica trivalor: (Gi {Fi,j} ∪ Fi Ti Ci Ki) (Gi {Fi,j \ L} ∪ Fi Ti Ci Ki) sólo si Fi,j \ L ∫ []. (B5) P(Fi,j) = L es un literal built-in de términos constantes que se evalúa a “falso” o “desconocido” aplicando la lógica trivalor: (Gi {Fi,j} ∪ Fi Ti Ci Ki) (Gi Fi Ti Ci Ki) donde P(Gi) y P(Fi,j) representan la función de selección de un literal, aplicada sobre el goal Gi y sobre una condition to enforce Fi,j, respectivamente; y L es por tanto el literal seleccionado. En cuanto a la formalización de las reglas, se muestran, separados por una línea, arriba el nodo CQC sobre el que se aplica la regla, y abajo el nodo CQC resultante de aplicar la regla. Finalmente, una última modificación consiste en definir dos nuevos predicados built-in que se añaden a los ya definidos por el método original. Estos predicados son: is null e is not null; dos predicados unarios que se pueden definir de la forma siguiente: X is null ⇔ la constante asignada a la variable X es la constante null X is not null ⇔ ¬ X is null Estos predicados son necesarios para la correcta traducción a lógica de las expresiones SQL IS NULL e IS NOT NULL. Una primera traducción en que se podría pensar seria: X = null y X ≠ null, respectivamente. Esta traducción es, pero, incorrecta; puesto que, tal y como se ha explicado, una comparación donde uno de los términos sea la constante null será tratada por el método de la misma forma que si se evaluara a “falso”. Así pues, se requiere de dos nuevos predicados built-in para poder expresarlo correctamente. 3.3. Ejemplo de derivación con valores nulos Para ilustrar el aspecto de una derivación CQC con valores nulos, recuperaremos el ejemplo motivador de la introducción, donde teníamos dos consultas Q1 y Q2 tales que, considerando valores nulos, Q1 ⋢ Q2. Para poder aplicar el método CQC es necesario traducir primero las dos consultas, Q1 y Q2, así como las restricciones de integridad del esquema, a lógica de primer orden. Esta traducción da como resultado las siguientes reglas de deducción y condiciones: q1(X) ← empleados(Y, X, Z) q2(X) ← empleados(Y, X, Z) ∧ categorias(U, V) ∧ Z = U ∧ V > 40000 ← categorias(X, null) ← empleados(X, null, Y) ← categorias(X, Y) ∧ Y ≤ 50000 ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z) aux(X) ← categorias(X, Y) Recordemos que la restricción de integridad referencial establece que una clave foránea puede tener o bien valor nulo, o bien un valor que aparezca en alguna fila de la columna o columnas referenciadas. Esto es lo que expresa la última condición (con su regla auxiliar), en forma negativa: no puede pasar que haya un empleado para el cual nombreCat tenga un valor no nulo y que no haya ninguna categoría con ese nombre. Por razones de espacio, se han obviado las restricciones de clave primaria ya que no tienen un efecto significativo (simplemente se comprobarían y se vería que no se violan) en esta derivación en concreto. Conditions to enforce ← q1(X) ∧ ¬q2(X) {← categorias(X, null), ← categorias(X, Y) ∧ Y ≤ 50000, ← empleados(X, null, Y), ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z)} 1:A1 {← categorias(X, null), ← empleados(Y, X, Z) ← categorias(X, Y) ∧ ¬q2(X) ∧ Y ≤ 50000, ← empleados(X, null, Y), ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z)} 2:A2 ← ¬q2(‘A’) 5:B2 ... ← ¬q2(‘A’) {40000, 50000} ∅ ∅ {40000, 50000} ∅ {40000, 50000, 0, ‘A’} {empleados(0, {← categorias(X, {40000, {← categorias(X, Y) ‘A’, null)} null)} ∧ Y ≤ 50000, 50000, 0, ‘A’} ← empleados(X, null, Y), ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z)} {← empleados(X, null, Y), {empleados(0, {← categorias(X, {40000, 50000, ‘A’, null)} ← empleados(X, Y, Z) null), 0, ‘A’} ∧ Z is not null ∧ ¬aux(Z)} ← categorias(X, Y) ∧ Y ≤ 50000} {← categorias(X, {← empleados(X, Y, Z) {empleados(0, {40000, null), ∧ Z is not null ∧ ¬aux(Z)} ‘A’, null)} 50000, ← categorias(X, 0, ‘A’} Y) ∧ Y ≤ 50000, ← empleados(X, null, Y)} ... 4:B2 ∅ ... 3:B2 ← ¬q2(‘A’) Conditions Constantes to maintain utilizadas ∅ {← categorias(X, null), {empleados(0, ← categorias(X, Y) ‘A’, null)} ∧ Y ≤ 50000, ← empleados(X, null, Y), ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z)} ... ← ¬q2(‘A’) EDB ... Goal to attain Figura 1. Primeros pasos de una derivación CQC que demuestra Q1 ⋢ Q2. En las figuras 1 y 2 se puede ver un ejemplo de derivación CQC con valores nulos, extraída del árbol CQC que el método explora para comprobar si Q1 ⊑ Q2. Esta derivación tiene éxito y construye un contraejemplo que demuestra la no contención de Q1 en Q2, cuando se permiten valores nulos. La figura muestra la secuencia de nodos CQC, uno por fila, y entre cada par de nodos indica la regla de expansión que se ha aplicado. Para cada nodo, el literal seleccionado se muestra subrayado. El nodo inicial tiene como conditions to enforce las condiciones resultantes de traducir las restricciones de integridad del esquema a lógica de primer orden. Puesto que se quiere comprobar si Q1 está contenida en Q2, el objetivo del método será construir una EDB en lo que suceda justo lo contrario, y de ahí el porqué del goal to attain inicial. En el primer paso, el método CQC selecciona el literal q1(X) y, al ser q1 un predicado derivado, aplica la regla A1 para “desplegar” este literal y sustituirlo por el cuerpo de su regla de deducción. ... Conditions Constantes to maintain utilizadas ... EDB ... Conditions to enforce ... ... Goal to attain 6:B2 ← ¬q2(‘A’) {← null is not null ∧ ¬aux(null)} {empleados(0, ‘A’, null)} C6* {empleados(0, ‘A’, null)} C6 {40000, 50000, 0, ‘A’} {empleados(0, ‘A’, null)} C6 {40000, 50000, 0, ‘A’} C6 {40000, 50000, 0, ‘A’} 7:B5 ← ¬q2(‘A’) ∅ 8:A3 [] {← q2(‘A’)} 9:B1 [] {← empleados(Y, ‘A’, Z) {empleados(0, ‘A’, null)} ∧ categorias(U, V) ∧ Z = U ∧ V > 40000} {40000, 50000, 0, ‘A’} 10:B2 C6 ∪ {empleados(0, {40000, {← empleados(Y, 50000, ‘A’, null)} 0, ‘A’} ‘A’, Z) ∧ categorias(U, V) ∧Z=U ∧ V > 40000} * C6 = {← categorias(X,null), ← categorias(X, Y) ∧ Y ≤ 50000, ← empleados(X, null, Y), ← empleados(X, Y, Z) ∧ Z is not null ∧ ¬aux(Z)} [] ∅ Figura 2. Últimos pasos de la derivación CQC que demuestra Q1 ⋢ Q2. En el paso 2, al seleccionar un literal positivo cuyo predicado se corresponde a una de las tablas de la BD, el método aplica la regla A2 para instanciar las variables de este literal y luego añadir la instancia a la EDB en construcción. En esta rama concreta del árbol CQC, se ha optado por asignar, aplicando el Negation VIP para las tres variables, a la variable Y la constante nueva 0, a la variable X la constante nueva ‘A’, y a la variable Z la constante null. En los pasos 3, 4 y 5 se aplica una regla B# puesto que el literal seleccionado pertenece a una condition to enforce. Concretamente, se aplica la regla B2 que comprueba si el literal seleccionado, que es positivo y se corresponde a una tabla de la BD, se puede unificar con alguno de la EDB. Al no ser esto posible ya es seguro que la restricción no se viola y por tanto ya se puede eliminar de las conditions to enforce, no sin antes añadirla a las conditions to maintain para poder volver a comprobarla en el futuro si fuera necesario. En el paso 6, la regla B2 sí puede unificar el literal seleccionado con el hecho presente en la EDB, lo cual supone la asignación de las constantes 0, ‘A’ y null a las variables X, Y y Z de esta condición. En el paso 7, el literal seleccionado tiene como predicado el predicado built-in is not null. Como ya se ha visto, este predicado unario se evalúa a falso cuando su término es la constante null, como es el caso. Así pues, toda la condición se evalúa a “falso” y no se viola. En el paso 8, el literal seleccionado es negativo así que se aplica la regla A3 y se añade una nueva contion to enforce que tendrá como cuerpo el literal sin la negación, puesto que el significado de la presencia de este literal en el goal es que la EDB que se construya no puede hacerlo “cierto”. En el paso 9, la regla B1 “despliega” el literal derivado. En el paso 10 y último, la regla B2 no puede unificar el literal seleccionado con ningún hecho de la EDB por lo que ya se puede decir que la condición no se viola. En este caso se ha seleccionado el literal correspondiente al predicado categorías en lugar del literal correspondiente al predicado empleados que también era susceptible de ser seleccionado. El método CQC no define ningún orden para la selección de literales; la única restricción es que los literales negados o built-in no se pueden seleccionar hasta que todos sus términos sean constantes. Dado que el nodo CQC resultante tras aplicar esta última regla de expansión tiene tanto el goal to attain como las conditions to enforce vacíos, se puede decir que se trata de un nodo solución, y la EDB que contiene es, por tanto, el contraejemplo que demuestra Q1 ⋢ Q2. 4. VALIDACIÓN DE ESQUEMAS DE BASES DE DATOS Como ya se ha comentado, una de las aplicaciones del método CQC es la validación de esquemas de BD. La herramienta SVT (Schema Validation Tool) [12] implementa el método CQC con el objetivo de realizar una serie de tests sobre un esquema de BD para comprobar si cumple ciertas propiedades deseables: satisfactibilidad del esquema, redundancia de restricciones de integridad, viveza de tablas y vistas, contención de vistas, así como comprobar si un cierto estado parcial de la BD, ya sea definido directamente a través de sus tuplas o mediante una consulta, es o no alcanzable sin violar ninguna restricción de integridad. Estas mismas propiedades se pueden comprobar teniendo en cuenta la posible presencia de valores nulos, utilizando la versión del método CQC extendida con valores nulos que aquí se ha explicado. Un prototipo de implementación de está versión extendida, que permite realizar los mismos tests que la herramienta SVT original, está disponible en forma de servicio web [10]. Una aplicación cliente, con interfaz web, para este servicio, se puede encontrar en http://folre.lsi.upc.edu. 5. CONCLUSIONES Y TRABAJO FUTURO En este artículo hemos abordado el problema de comprobar la contención de consultas teniendo en cuenta la posible presencia de valores nulos en los atributos de las tuplas. Según nuestro conocimiento, ninguno de los trabajos hechos hasta ahora en relación con la contención de consultas consideraba la presencia de valores nulos. Para realizar esta comprobación hemos extendido nuestro método CQC para que pueda tratar con valores nulos. El método CQC es correcto y completo, y permite tratar con restricciones de integridad, negación safe tanto en predicados EDB como IDB, y predicados built-in. La demostración formal de la corrección y completitud de la versión del método CQC extendida con valores nulos queda pendiente como trabajo a realizar a continuación. Además, las ideas expuestas en este artículo se han implementado en forma de un servicio web dedicado a la validación de esquemas de bases de datos relacionales, aplicando la versión extendida del método CQC en la realización de una serie de tests sobre los esquemas y permitiendo así comprobar ciertas propiedades deseables teniendo en cuenta que la BD puede contener valores nulos. REFERENCIAS [1] Nieves R. Brisaboa, Héctor J. Hernández: Testing Bag-Containment of Conjunctive Queries. Acta Inf. 34(7): 557-578 (1997). [2] A.K. Chandra, P.M. Merlin. Optimal Implementation of Conjunctive Queries in Relational Data Bases. In Proceedings of the 9th ACM SIGACT Symposium on Theory of Computing: 77-90, 1977. [3] Carles Farré, Ernest Teniente, Toni Urpí: A New Approach for Checking Schema Validation Properties. DEXA 2004: 77-86. [4] Carles Farré, Ernest Teniente, Toni Urpí: Checking query containment with the CQC method. Data Knowl. Eng. 53(2): 163-223 (2005). [5] A. Gupta, Y. Sagiv, J.D. Ullman, J. Widom. Constraint Checking with Partial Information. In Proceedings of the 13th ACM SIGACT-SIGMOD-SIGART Symposium on Principles of Database Systems (PoDS’94): 45-55, 1994. [6] A.Y. Halevy. Answering queries using views: A survey. VLDB Journal, 10(4): 270294, 2001. [7] Yannis E. Ioannidis, Raghu Ramakrishnan: Containment of Conjunctive Queries: Beyond Relations as Sets ACM Trans. Database Syst. 20(3): 288-324 (1995). [8] D.S. Johnson, A. Klug. Testing Containment of Conjunctive Queries under Functional and Inclusion Dependencies. Journal of Computer and System Sciences, 28(1):167189, 1984. [9] A. Levy, Y. Sagiv. Queries Independent of Updates. In Proceedings of the 19th International Conference on Very Large Data Bases (VLDB’93): 171-181, 1993. [10] Guillem Rull. Servei Web de Validació d’Esquemes de BD. Proyecto Final de Carrera, Universitat Politècnica de Catalunya, 2006. URL: http://folre.lsi.upc.edu/svws/ memoriaPFC.pdf. [11] Y. Sagiv, M. Yannakakis. Equivalences Among Relational Expressions with the Union and Difference Operators. Journal of the ACM, 27(4):633-655, 1980. [12] Ernest Teniente, Carles Farré, Toni Urpí, Carlos Beltrán, David Gañán: SVT: Schema Validation Tool for Microsoft SQL-Server. VLDB 2004: 1349-1352. [13] J.D. Ullman. Principles of Database and Knowledge-Base Systems, Volume 2: The New Technologies. Computer Science Press, 1989.