Pregunta

Fondo

Recientemente he comenzado a utilizar XML mucho más como una columna en SQL Server 2005. Durante un poco de tiempo de inactividad de ayer, me di cuenta de que dos de las mesas de enlace He utilizado una realidad sólo en la forma y me aburre lágrimas, teniendo aún más apoyo para escribir código de estructura para un par de uniones.

Para realmente generar los datos para estas dos tablas del acoplamiento, paso en dos campos XML a mi procedimiento almacenado, que escribe el registro principal, se rompe las dos variables XML abajo en @tables e insertos de ellos en las tablas reales con el nuevo SCOPE_IDENTITY() del registro maestro.

Después de un poco, sin embargo, decidí simplemente acabar con esas tablas por completo y sólo almacenar el XML en campos XML. Ahora entiendo que hay algunos errores aquí, al igual que el rendimiento general de consulta, GROUP BY no funciona en los datos XML. Y la consulta es generalmente un poco de desorden, pero en general al igual que ahora pueden trabajar con XElement cuando llegue a la parte posterior de los datos.

Además, esto no va a cambiarse. Es un asunto de un solo tiro, por lo que no tiene que preocuparse de modificación.

Me pregunto cuál es la mejor manera de conseguir realmente en estos datos. Muchas de mis consultas implican la obtención de un registro maestro en base a los criterios de un niño o incluso un registro subchild. La mayoría de los procedimientos almacenados en la base de datos hacer esto, pero en una escala mucho más elaborado, por lo general requieren UDF y subconsultas para trabajar con eficacia, pero he golpeado un ejemplo trivial a prueba de consultar algunos datos ...

INSERT INTO Customers VALUES ('Tom', '', '<PhoneNumbers><PhoneNumber Type="1" Value="01234 456789" /><PhoneNumber Type="2" Value="01746 482954" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Andy', '', '<PhoneNumbers><PhoneNumber Type="2" Value="07948 598348" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Mike', '', '<PhoneNumbers><PhoneNumber Type="3" Value="02875 482945" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Steve', '', '<PhoneNumbers></PhoneNumbers>')

Ahora puede ver dos formas de acaparamiento.

Método 1

DECLARE @PhoneType INT
SET  @PhoneType = 2

SELECT ct.*
FROM Customers ct
WHERE ct.PhoneNumbers.exist('/PhoneNumbers/PhoneNumber[@Type=sql:variable("@PhoneType")]') = 1

En serio? SQL: Variable siente un poco malsana. Sin embargo, funciona. Sin embargo, es claramente más difícil acceder a los datos de una manera más significativa.

Método 2

SELECT ct.*, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') = @PhoneType

Esto es más como él. Ya puedo ampliar fácilmente para hacer combinaciones y todas las otras cosas buenas. He usado CROSS APPLY antes de una función con valores de tabla, y fue muy bueno. El plan de ejecución para esta oposición a la consulta anterior es serio más avanzada. Es cierto que no he hecho ninguna indexación y otras cosas en estas tablas, pero es el 97% del costo total del lote.

Método 2 (expandido)

SELECT ct.ID, ct.CustomerName, ct.Notes, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') IN (SELECT ID FROM PhoneTypes)
cláusula IN

Niza aquí. También puedo hacer algo como pt.PhoneType = 'Work'

Finalmente

Así que estoy Obtendré esencialmente los resultados que quiero, pero ¿hay algo que deba tener en cuenta al utilizar este mecanismo para interrogar a pequeñas cantidades de datos XML? Va a caer en el rendimiento durante los registros elaborados? Y es el almacenamiento de dichos datos de estilo marcado demasiado de una sobrecarga?

Nota al margen

He usado cosas como sp_xml_preparedocument y OPENXML en el pasado sólo para pasar listas en sprocs, pero esto es como un soplo de aire fresco en comparación!

¿Fue útil?

Solución

Uno de los enfoques que hemos tomado para algunos de nuestros artículos clave de la información almacenada en el interior de una columna XML es "superficial" como computada, persistieron propiedades sobre la mesa "padre". Esto se hace usando un poco de función almacenada.

Funciona muy bien, ya que el valor se calcula sólo una vez cada vez que cambia el XML -., Siempre y cuando no se está cambiando, no hay recálculo, el valor se almacena en la mesa como cualquier otra columna

También es ideal, ya que puede ser indexado! Así que si usted está buscando y / o unirse en un campo tan - que funciona como un encanto

!

Así que básicamente necesita una función almacenada en la línea de lo siguiente:

CREATE FUNCTION [dbo].[GetPhoneNo1](@DataXML XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
      DECLARE @result VARCHAR(20)

      SELECT 
        @result = @DataXML.value('(/PhoneNumbers/PhoneNumber[@Type="1"]/@Value)[1]', 'VARCHAR(50)')
      RETURN @result
END

Si usted no tiene un número de teléfono de tipo 1, vas a volver a NULL.

A continuación, es necesario ampliar su tabla padre con una columna calculada, persistió:

ALTER TABLE dbo.Customers
   ADD PhoneNumberType1 AS dbo.GetPhoneNo1(PhoneNumbers)

Como se puede ver - que funciona muy bien para las entradas individuales, pero, por desgracia, no puede surgir toda una lista de propiedades. Pero si usted tiene algunos elementos clave, como el identificador del o algo así, que espera la mayoría de sus filas a tener, esto puede ser una forma muy agradable y pulido de conseguir por lo que la información más fácilmente y con mayor eficiencia.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top