2009-10-09 9 views
6

Tabloda, xml verilerini depolamak için kullanılan bir varchar sütunu var. Evet, kullanmam gereken bir xml veri türü olduğunu biliyorum, ancak bunun, xml veri türü kullanıma sunulmadan önce kurulduğunu düşünüyorum, bu yüzden şu anda kullanmak zorunda olduğum bir varchar. :) saklananSQL Server xml dizgisi varchar alanında ayrıştırma

verileri aşağıdaki benzer:

<xml filename="100100_456_484351864768.zip" 
    event_dt="10/5/2009 11:42:52 AM"> 
    <info user="TestUser" /> 
</xml> 

Ben bu durumda "456" olacağını iki alt çizgi arasındaki rakamları elde etmek dosya adını ayrıştırmak gerekir. Dosya adının ilk kısmı "olmamalıdır" uzunluğunu değiştirmelidir, ancak orta sayı olacaktır. İlk bölümün uzunluğu değiştiğinde işe yarayacak bir çözüme ihtiyacım var (değişeceğini biliyorsunuz çünkü "değişmemeli" her zaman değişeceği anlamına geliyor).

Şimdilik elimde olan için, dosya adını çıkarmak için XQuery kullanıyorum çünkü bunun muhtemelen düz dize manipülasyondan daha iyi olduğunu düşündüm. Bunu yapmak için dizeyi xml'ye döküyorum, ama XQuery uzmanı değilim, tabii ki sorunlara bakıyorum. XQuery (substring-before) için bir işlev buldum, ancak çalışmaya başlayamadım (bu işlevin SQL Server ile çalışacağından bile emin değilim). Bunu kolayca yapabilmek için bir XQuery işlevi olabilir, ancak eğer bunun farkında olmasaydım. Ben sonra bazı yapmak bir dizeye bu geri CAST mümkün olacağını varsaymak istiyorum Bundan

select CAST(parms as xml).query('data(/xml/@filename)') as p 
from Table1 

:

Yani, aşağıdakine benzer bir sorgu ile tablodan dosya adı almak Alt simgelerin nerede olduğunu anlamak için instring veya charindex işlevi, ihtiyacım olan parçayı seçmek için tüm bunları bir altdizgeme fonksiyonunda kapsülleyebilir. Bu konuya çok fazla girmeden, sonunda böyle bir şey yapabildiğime eminim, ama daha kolay bir yolun olması gerektiğini biliyorum. Bu şekilde, SQL deyiminde büyük bir okunamaz alan oluşturabilirdi; bu, bir işleve taşınsa bile, neler olup bittiğini anlamaya çalışmak için kafa karıştırıcı olurdu.

Basit bir dize manipülasyonu olduğu için bundan daha kolay olduğundan eminim. Belki birisi bana doğru yönde işaret edebilir. Teşekkürler

+1

SQL Server'ın hangi sürümü? –

+0

Üzgünüz, şu ana kadar bu yorumu görmedim. Şimdi SQL Server 2008 kullanıyoruz. – Dusty

cevap

5

Bunun için XQuery kullanabilirsiniz - sadece geçerli herhangi bir dosya adı ve yolu tutmak için yeterince uzun sana bir VARCHAR (260) verir

SELECT 
    CAST(parms as xml).value('(/xml/@filename)[1]', 'varchar(260)') as p 
FROM 
    dbo.Table1 

- şimdi bir dize sahip olduğunu ve SUBSTRING

Marc ile üzerine çalışabilirsiniz: sizin deyimini değiştirmek

+0

Yanıt verdiğiniz için teşekkür ederim, ancak bu yazıyı, .value yerine .query kullanarak yaptığım sorguda bulabildim. Anladığım kadarıyla dosya ismini ayrıştırmanın en iyi yolunu arıyordum. Ancak, şimdi konu üzerinde olduğumuz, .query veya .value kullanmak için tercih edilen yöntemdir? – Dusty

+1

'query()', "XML" veri türünün bir örneği olarak tüm bir XDM sonuç ağacını döndürür; 'value()', sorgunuzun yalnızca tek bir XDM değeri döndürmesini ve bunu bazı SQL türlerine dönüştürmesini gerektirir. Genel olarak, bir XML belgesini veya parçasını veya en azından bir düğüm kümesi döndürdüğünüzde ve yalnızca tek bir değer döndürmeniz gerektiğinde, ikincisi için önce siz gidin. –

+0

Teşekkürler. Bu mantıklı. Size herhangi bir puan vermese de, yorumunuzu destekledim. :) – Dusty

1

Ne yazık ki, SQL Server uyumlu bir XQuery uygulaması değil, XQuery özelliklerinin bir taslağının oldukça sınırlı bir alt kümesidir. Sadece fn:substring-before değil, aynı zamanda fn:substring veya fn:string-to-codepoints kullanarak bunu yapmak için fn:index-of yoktur. Yani, anlayabildiğim kadarıyla, burada SQL ile sıkışmışsın.

+0

+1 Teşekkürler, SQL Server'ın sınırlı bir XQuery alt kümesine sahip olduğundan korkuyordum. Görünüşe göre, sanki Steve Kass'in söylediği gibi, bunu yapmak için SQL Server'da substring fonksiyonunu kullanmam gerekecek. – Dusty

4

Bunu yapmanın en basit yolu, SUBSTRING ve CHARINDEX. (Bilge ya da değil) dosya adı ilk bölümü uzunluğu değişmez varsayarsak, ama yine de dosya adını bulmak XQuery kullanmak istediğiniz, burada kısa bir üreme istediğini olmadığını açıklanmıştır: Orada

declare @t table (
    parms varchar(max) 
); 
insert into @t values ('<xml filename="100100_456_484351864768.zip" event_dt="10/5/2009 11:42:52 AM"><info user="TestUser" /></xml>'); 

with T(fName) as (
    select cast(cast(parms as xml).query('data(/xml/@filename)') as varchar(100)) as p 
    from @t 
) 
    select 
    substring(fName,8,charindex('_',fName,8)-8) as myNum 
    from T; 

REPLACE ve PARSENAME veya REVERSE gibi diğer dize işlevlerini kullanan gizli çözümlerdir, ancak hiçbiri daha verimli veya okunabilir değildir. Göz önünde bulundurulması gereken bir olasılık, düzenli ifade işleminin SQL'e getirilmesini sağlayan bir CLR yordamı yazmaktır.

Bu arada, xml'niz her zaman bu kadar basitse, XQuery'yi kullanmak için görebildiğim belirli bir sebep yok. İstediğiniz numarayı çıkaracak iki sorgu var.Eğer xml dizesinde veya dosya adının ilk bölümü uzunluğunu değiştirmek bulunabileceği ihtimalini üzerinde ekstra boşluk üzerinde kontrol yoksa ikinci güvenlidir:

select 
    substring(parms,23,charindex('_',parms,23)-23) as myNum 
    from @t; 

    select 
    substring(parms,charindex('_',parms)+1,charindex('_',parms,charindex('_',parms)+1)-charindex('_',parms)-1) as myNum 
    from @t; 
+0

+1 Düşündüğüm şeyi yapmak zorunda kalacağım gibi görünüyor. Bunu yapmak için SQL Server substring'i kullanmak zorunda kalacağım. Cevabını takdir ediyorum ve benim için çalışmanın çoğunu yapıyorum. İlk yazıya benzer bir şey yapan bir işlev yapacağımı düşünüyorum, ancak bu durumda göndereceğiniz ikinci kod örneği çalışacaktı, ancak XQuery'yi string manipülasyonunu yapmadan önce dosya ismini çıkarmak için kullanmayı tercih ediyorum. Yardımınız için tekrar teşekkürler ve bunu cevap olarak işaretleyeceğim. – Dusty