So, nach ein wenig google etwas Arbeit habe ich jetzt ein Lösung gefunden, die sogar recht performant aussieht.
Zunächst noch ein paar Basics:
Die Tabelle ASPNET_PROFILE beinhaltet folgende Felder:
- UserId
- PropertyNames
- PropertyValuesString
- PropertyValuesBinary
- LastUpdatedDate
Das Feld PropertyNames beinhaltet eine mit ":" separierte Zeichenfolge, die definiert welche Benutzereigenschaften / -properties gespeichert werden. Zusätzlich wird die Position dort angegeben. Ein Beispiel:
FirstName:S:39:7
Dieser (Teil-)Eintrage besagt das die Property den Namen "FirstName" hat, vom Typ String "S" ist, an der Postion 39 anfängt und 7 Zeichen lang ist.
Um nun einzelene Daten zur extrahieren, habe ich mir eine die Funktionalität der UDF (User Defined Functions) vom Microsoft SQL Server bzw. der MSDE zu nutze gemacht. Diese Funktionen können direkt aus SQL-Statements aufgerufen werden.
CREATE FUNCTION dbo.GaliNeo_UDF_GetElement
(
@ord AS INT,
@strToParse AS VARCHAR(8000),
@seperator AS VARCHAR(1)
)
RETURNS INT
AS
BEGIN
-- Wenn die Eingabeparatemer null sind, wird auch null zurück gegeben
IF @strToParse IS NULL
OR LEN(@strToParse) = 0
OR @ord IS NULL
OR @ord < 1
OR @ord > LEN(@strToParse) - LEN(REPLACE(@strToParse, @seperator, '')) + 1
RETURN NULL
DECLARE @ipos AS INT, @curord AS INT
SELECT @ipos = 1, @curord = 1
-- nächsts Element suchen
WHILE @curord < @ord
SELECT
@ipos = CHARINDEX(@seperator, @strToParse, @ipos) + 1,
@curord = @curord + 1
RETURN CAST(SUBSTRING(@strToParse, @ipos, CHARINDEX(@seperator, @strToParse + @seperator, @ipos) - @ipos) AS INT)
END
Die GaliNeo_UDF_GetElement ist eine sehr allgemein Funktion um mit separierte Strings in SQL-Queries zu arbeiten. Sehr hilfreich war dabei ein Artikel auf der Seite WindowsItPro.
Diese Funktion können wir nun in der eigentlichen UDF "GaliNeo_UDF_GetProfileElement" nutzen:
CREATE FUNCTION dbo.GaliNeo_UDF_GetProfileElement
(
@fieldName AS NVARCHAR(100),
@fields AS NVARCHAR(4000),
@values AS NVARCHAR(4000)
)
RETURNS NVARCHAR(4000)
AS
BEGIN
IF @fieldName IS NULL
OR LEN(@fieldName) = 0
OR @fields IS NULL
OR LEN(@fields) = 0
OR @values IS NULL
OR LEN(@values) = 0
RETURN NULL
DECLARE @fieldNameToken AS NVARCHAR(20)
DECLARE @fieldNameStart AS INTEGER, @valueStart AS INTEGER, @valueLength AS INTEGER
SET @fieldNameStart = CHARINDEX(@fieldName + ':S',@Fields,0)
IF @fieldNameStart = 0 RETURN NULL
SET @fieldNameStart = @fieldNameStart + LEN(@fieldName) + 3
SET @fieldNameToken = SUBSTRING(@Fields,@fieldNameStart,LEN(@Fields)-@fieldNameStart)
SET @valueStart = dbo.GaliNeo_UDF_GetElement(1,@fieldNameToken,':')
SET @valueLength = dbo.GaliNeo_UDF_GetElement(2,@fieldNameToken,':')
IF @valueLength = 0 RETURN ''
RETURN SUBSTRING(@values, @valueStart+1, @valueLength)
END
Aus einer SQL Query kann jetzt diese Funktion wie folgt genutzt werden:
SELECT dbo.GaliNeo_UDF_GetProfileElement('PostalCode',PropertyNames,PropertyValuesString) FROM aspnet_Profile
So, das tat doch mal wieder fast nicht weh und bei 10.000 Profilen ist es von der Performance noch in Ordnung. Mal schauen wie es sich verhält, wenn man etwas mehr Daten in er DB hat.