Синтаксис ORDER BY со столбцом XML в SQL 2005 - PullRequest
2 голосов
/ 23 января 2009

У меня есть профиль пользователя (более одного профиля в зависимости от типа пользователя), который я храню в столбце БД (xml).

Я могу запросить это с помощью XPATH в моей хранимой процедуре, однако я не уверен, как затем выполнить ORDER BY.

SELECT U.UserId, UP.Profile, UP.UserParentID
FROM aspnet_Users U
LEFT OUTER JOIN UserProperties UP ON U.UserId = UP.UserId
WHERE
UP.Profile.exist('/Properties/property[contains(.,sql:variable("@cLookup"))]') = 1

Пример XML:

<Properties>
            <property id="BusinessName" name="Business Name"></property>
            <property id="AccountNumber" name="Account Number"></property>
            <property id="Address" name="Address"></property>
            <property id="Phone" name="Phone"></property>
            <property id="Fax" name="Fax"></property>
            <property id="Web" name="Web"></property>
            <property id="ABN" name="ABN"></property>
            <property id="Logo" name="Logo"></property>
            <property id="Photos" name="Photos"></property>
            <property id="Map" name="Location Map"></property>
        </Properties>

И

<Properties>
            <property id="FirstName" name="First Name"></property>
            <property id="LastName" name="Last Name"></property>
        </Properties>

Хотел бы ЗАКАЗАТЬ ПО BusinessName

Ответы [ 2 ]

0 голосов
/ 28 января 2009

Другой вариант, на который вы можете посмотреть - это вычисляемые столбцы, особенно если у вас есть один или несколько часто используемых столбцов.

В общем случае вычисляемый столбец - это просто столбец, значение которого вычисляется из чего-то другого и является актуальным в любое время, при этом вам не нужно постоянно его обновлять.

В сочетании с XML вы можете написать небольшую хранимую функцию и использовать ее для создания вычисляемого столбца в вашей «базовой» таблице, чтобы вы могли запрашивать и упорядочивать по этому столбцу без необходимости «доходить» до XML время.

В данном случае вы можете написать хранимую функцию для извлечения «BusinessName» и сделать ее доступной в вашей таблице UserProfile, например:

CREATE FUNCTION dbo.GetBusinessName(@input XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
  DECLARE @Result VARCHAR(50)

  SELECT 
    @Result = @input.value('(Properties/property[@id="BusinessName"]/@name)[1]', 'VARCHAR(50)')

  RETURN @Result
END

Это определяет хранимую функцию, которая будет принимать ваш профиль XML и искать «свойство» с «id» в «Business Name» и возвращать свой атрибут «name» обратно.

Чтобы добавить это в таблицу UserProfile, используйте этот код SQL:

ALTER TABLE UserProfile
    ADD BusinessName AS dbo.GetBusinessName(Profile) PERSISTED

При этом вы добавляете новое вычисляемое поле с именем «BusinessName» в свою таблицу, и теперь вы можете выбирать и заказывать с помощью этого нового поля, например,

SELECT ID, BusinessName FROM UserProfiles ORDER BY BusinessName

Наслаждайтесь!

PS: Несколько слов о производительности: я обнаружил, что во многих случаях это на намного быстрее, чем постоянное выполнение запроса XML в поле XML. Поэтому, если у вас есть определенные элементы в XML, к которым вам часто требуется доступ, или которые могут отображаться в операторе ORDER BY, использование вычисляемого столбца на самом деле может значительно ускорить процесс.

0 голосов
/ 23 января 2009

Считайте этот ответ незавершенным, потому что я не уверен, что это правильный запрос.

Ответ заключается в использовании функции .nodes () в сочетании с .value (), чтобы вы могли извлечь значение для атрибута «name» из элемента с «BusinessName» в качестве значения «id» приписывать.

Существует небольшое руководство по использованию .nodes () для замены старого синтаксиса OPENXML здесь .

В любом случае, вот запрос, как он есть. Попробуйте это на ваших данных, и давайте посмотрим, сможем ли мы изменить это, пока оно не заработает.

SELECT U.UserId, UP.Profile, UP.UserParentID
FROM aspnet_Users U
    LEFT OUTER JOIN UserProperties UP ON U.UserId = UP.UserId
    OUTER APPLY UP.Profile.nodes('/Properties/property') p(prof)

WHERE UP.Profile.exist('/Properties/property[contains(.,sql:variable("@cLookup"))]') = 1
    AND p.prof.value('@id', 'nvarchar(20)') = 'BusinessName'

ORDER BY p.prof.value('@name', 'nvarchar(100)')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...