Domanda

Sfondo

Di recente ho iniziato ad usare XML molto più come una colonna in SQL Server 2005. Nel corso di un po 'di tempo morto ieri, ho notato che due delle tabelle di collegamento che ho usato una realtà solo nel modo e che mi annoia a lacrime dover scrivere ancora più supporto codice struttura per un paio di join.

Per effettivamente generare i dati per queste due tabelle di collegamento, passo a due campi XML alla mia stored procedure, che scrive il record principale, rompe le due variabili di XML giù in @tables e li inserisce nelle tabelle attuali con il nuovo SCOPE_IDENTITY() dal record master.

Dopo un po ', però, ho deciso di fare proprio finita con tali tabelle del tutto e solo memorizzare l'XML in campi XML. Ora ho capito ci sono alcuni trabocchetti qui, come le prestazioni generali di interrogazione, GROUP BY non funziona su dati XML. E la query è in genere un po 'di confusione, ma nel complesso come quello che posso ora lavorare con XElement quando ottengo la parte posteriore dei dati.

Inoltre, questa roba non sta andando per avere cambiato. E 'un affare un solo colpo, in modo da non devono preoccuparsi di modifica.

Mi chiedo circa il modo migliore per ottenere effettivamente a questi dati. Un sacco di mie domande coinvolgere ottenere un master record in base ai criteri di un bambino o anche un record subchild. La maggior parte dei sprocs nel database fare questo, ma su scala molto più elaborato, di solito richiede UDF e subquery di lavorare efficacemente, ma ho messo incinta un esempio banale per testare l'interrogazione di alcuni dati ...

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>')

Ora posso vedere due modi di afferrare esso.

Metodo 1

DECLARE @PhoneType INT
SET  @PhoneType = 2

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

Davvero? sql: variable si sente un po 'malsana. Tuttavia, funziona. Tuttavia è tipicamente più difficile accedere ai dati in modo più significativo.

Metodo 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

Questo è più simile. Già Posso facilmente espanderlo a fare unisce e tutte le altre cose buone. Ho usato CROSS APPLY prima su una funzione con valori di tabella, ed è stato molto buono. Il piano di esecuzione per questo in contrasto con la query precedente è seriamente più avanzato. Devo ammettere che non ho fatto alcuna indicizzazione e quant'altro su queste tabelle, ma è il 97% dell'intero costo batch.

Metodo 2 (ampliato)

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)
Clausola IN

bello qui. Posso anche fare qualcosa di simile pt.PhoneType = 'Work'

Infine

Quindi sono essenzialmente ottenendo i risultati che voglio, ma c'è qualcosa che dovrei essere a conoscenza di quando si utilizza questo meccanismo per interrogare piccole quantità di dati XML? Sarà cadere sulle prestazioni durante le ricerche elaborate? Ed è la conservazione di tali dati di stile di markup troppo di un sovraccarico?

Nota a margine

Ho usato le cose come sp_xml_preparedocument e OPENXML in passato solo per passare liste in sprocs, ma questo è come una boccata d'aria fresca in confronto!

È stato utile?

Soluzione

Un approccio che abbiamo adottato per alcuni dei nostri articoli principali di informazioni memorizzate all'interno di una colonna XML è quello di "superficie" loro come calcolato, persistevano proprietà sul tavolo "padre". Questo viene fatto usando un po 'di funzione memorizzata.

E le grandi opere, perché il valore viene calcolato solo una volta ogni volta che cambia XML -. Fintanto che non sta cambiando, non c'è ricalcolo, il valore viene memorizzato sul tavolo come qualsiasi altra colonna

E 'anche ideale perché può essere indicizzato! Quindi, se siete alla ricerca e / o partecipare a un tale campo - che funziona come un fascino

!

Quindi è fondamentalmente bisogno di una funzione memorizzata sulla falsariga di questo:

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

Se non si dispone di un numero di telefono di tipo 1, ti basta tornare indietro di un NULL.

Quindi, è necessario estendere la vostra tabella padre con una colonna calcolata, insistette:

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

Come si può vedere - funziona bene per le singole voci, ma purtroppo, non si può affiorare un intero elenco di proprietà. Ma se si dispone di alcuni elementi chiave, come ID del o qualcosa, che ci si aspetta la maggior parte delle righe da avere, questo può essere un modo molto bello e chiazza di petrolio per arrivare a tali informazioni più facilmente e in modo più efficiente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top