Сложная проблема с обновлением - PullRequest
1 голос
/ 01 сентября 2009

У меня есть следующая структура таблицы следующим образом: (пожалуйста, игнорируйте черный ящик. Форматировал вопрос в Excel)

альтернативный текст http://img525.imageshack.us/img525/5788/beforeznj.jpg

Что мне нужно сделать, это преобразовать данные SessionGUID в следующее с помощью TSQL: альтернативный текст http://img4.imageshack.us/img4/4553/afterjer.jpg

Это таблица пользовательских сессий для моего веб-сайта, и мы облажали SessionGUID, так как он генерировал NEWID () при каждой загрузке страницы. Поэтому теперь нам нужно сгруппировать сеансы по времени (при условии, что сеанс прерывается, если пользователь не запускает загрузку страницы через 30 минут после последней загрузки страницы), используя первый созданный SessionGUID.

Просто чтобы пояснить краткий пример, Пользователь (00000000-0000-0000-0000-000000000000) дважды посетил мой сайт 01.09.2009. Один в 13:37, а другой в 14:46. Пользователь (A107EF1E-00A2-4515-A120-984086BC8368). Обратите внимание, что фактическая таблица содержит миллион строк, которые необходимо обновить. (

UPDATE Целевая страница / начальный URL для каждого сеанса не всегда является «домашней страницей», это может быть любая страница на веб-сайте. Сюжет утолщается ..

ОБНОВЛЕНИЕ2 Данные испытаний

CREATE TABLE Sessions (IPAddress VARCHAR(15), UserGUID UNIQUEIDENTIFIER, DATE DATETIME, URL VARCHAR(200), SessionGUID UNIQUEIDENTIFIER)
INSERT INTO Sessions (
    IPAddress,
    UserGUID,
    DATE,
    URL,
    SessionGUID
)
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  13:37:34', 'homepage', '2B3A80B1-A247-4BB5-81BB-B54DED0C9C6A')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  13:37:36', 'page1', '7FB10E12-5EB9-428C-BE3E-57818DEF8512')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  13:37:41', 'page2', 'D12C3539-1239-447E-8BD8-DBA6B7087ADE')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  14:56:00', 'homepage', '4FE36C46-640B-464F-8118-AFFE477347A1')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  14:56:10', 'page2', 'FF9BF55B-3630-4D05-AB57-1B6ECAB96657')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  14:56:18', 'page4', '863D3424-9788-481A-8440-09313ED4F8FE')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  14:56:19', 'page3', '105D7FE5-C731-4EB6-B287-720127AAF0A3')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  15:00:35', 'page5', '296479D0-3848-4189-94E2-41906BAE580D')
VALUES ( '192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009  15:00:36', 'page7', 'E3FFEBC6-C11E-4DF4-81FA-B42F1BF7AFD3')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009  18:30:22', 'homepage', '1F918AB3-34E1-4343-8462-FA56423B921D')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009  18:34:26', 'page1', '801C3DC8-F0F3-4B9C-BD53-BCCBE784CFAE')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009  18:38:17', 'page2', 'A9A5C2BD-31B9-4A9B-A8BC-88C460F17282')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009  11:42:27', 'page3', 'B29CE754-C7A3-40E8-8CB0-216A3E852762')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009  11:42:32', 'page4', 'E291C4B9-A422-4A76-A550-F65C208DD886')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009  11:44:51', 'page6', '63D4A636-8336-44E7-8C97-9CD65D21359E')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009  11:44:55', 'page2', '7BB814CD-C9B3-4CAF-A45C-4405DC0B07D2')
VALUES ( '212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009  11:48:35', 'page4', 'B6DCEC1E-C262-425D-8E46-8F4B47F2921A')

Спасибо.

Несчастный новобранец DBA.

Ответы [ 3 ]

1 голос
/ 01 сентября 2009

РЕДАКТИРОВАТЬ У меня был ряд синтаксических ошибок, так как я не тестировал. (Примечание для себя, не отправляйте ответы без тестового кода.) И наконец, как только я исправил синтаксис и столкнулся с тестовыми данными, я обнаружил, что мой ответ был неправильным. Проверка подзапроса на наличие ряда за тридцать минут до этого была полностью поддельной.

Исправленная версия:

; with EliminateTies (UserGuid, SessionGuid, "Date") as
    (select UserGuid
        , cast(min(cast(SessionGuid as varbinary)) as uniqueidentifier)
        , "Date"
    from Sessions
    group by UserGuid, "Date")
, SessionBoundaries (UserGuid, SessionGuid, StartDateTime, SessionNumber) as
    (select UserGuid, SessionGuid, "Date"
        , row_number() over 
            (partition by UserGuid 
            order by "Date") as SessionNumber
    from (select UserGuid, SessionGuid, "Date" from EliminateTies
        union all
        -- Add a set of records at the end of time, to bound the last
        -- of each users sessions
        select distinct UserGuid
            , null as SessionGuid
            , cast('9999-12-31' as datetime) as "Date"
        from Sessions) ET_Out
    where not exists (select *
        from EliminateTies ET_In
        where ET_Out.UserGuid = ET_In.UserGuid
        and ET_Out.SessionGuid <> ET_In.SessionGuid
        and (dateadd(minute, -30, ET_Out."Date") < ET_In."Date" 
            and ET_In."Date" <= ET_Out."Date")))
Update MT
    set SessionGuid = LowBound.SessionGuid
from SessionBoundaries LowBound
inner join SessionBoundaries HighBound
    on LowBound.UserGuid = HighBound.UserGuid
    and LowBound.SessionNumber = HighBound.SessionNumber - 1
inner join Sessions S
    on S.UserGuid = LowBound.UserGuid
    and LowBound.StartDateTime <= S."Date" 
    and S."Date" < HighBound.StartDateTime

РЕДАКТИРОВАТЬ 2 Добавление объяснения:

  1. ; with EliminateTies ... Определить отношение, называемое EliminateTies. Это сделано для того, чтобы учесть, что тройки (UserGuid, SessionGuid, "Date") могут содержать дубликаты для данного (UserGuid, "Date"). SQL Server datetime имеет разрешение 1/300 секунды, поэтому дублирование маловероятно, но не невозможно.
    1. EliminateTies будет содержать строку для каждой (UserGuid, "Date") пары group by UserGuid, "Date".
    2. SessionGuid выбирается произвольно из набора SessionGuid s, доступных для этой пары с помощью функции агрегирования min(). Как указано в комментарии, MIN(GUID) не допускается, поэтому выполняется приведение к VARBINARY, обнаруживается MIN(), а затем приведение к UNIQUEIDENTIFIER.
    3. Примечания:
      1. Я начинаю с точки с запятой, потому что, хотя SQL Server обычно не требует точки с запятой в конце оператора, он делает это в случае с оператором, который предшествует with ... Вместо попытки переобучиться, чтобы завершить все операторы с помощью точки с запятой, я научил себя запускать все with ... с помощью точки с запятой. Точка с запятой фактически завершает любое предыдущее утверждение.
      2. Я цитирую идентификатор «Дата», потому что дата является типом данных в SQL Server 2008 и, следовательно, является зарезервированным словом. ОП на 2005 год, так что строго не нужно.
  2. , SessionBoundaries Еще одно отношение определяется. Это отношение имеет все точки, где начинается новый сеанс на основе правила, которое для данного сеанса UserGuid начинается, когда в сеансах нет записей в течение последних 30 минут.
    1. Встроенное представление from (select ... union all ...) ET_Out Добавляет дополнительную строку с датой в конце времени для каждого UserGuid. Это потому, что мы хотим сгруппировать строки между верхней и нижней границами, и нам нужна верхняя граница для последнего сеанса каждого пользователя.
    2. where not exists отфильтровывает строки, которые не находятся в начале границы сеанса.
    3. В предложении select row_number() ... будет нумеровать строки, упорядоченные по дате, чтобы каждый UserGuid имел SessionNumber s 1..N + 1, где N - количество сеансов. Позже мы используем SessionNumbers для поиска соседних границ. (Лучше бы назвали SessionBoundaryNumber.)
  3. И, наконец, обновление. Мы добавили предложение from, чтобы разрешить объединять отношения. Обновление задает псевдоним таблицы, которую мы хотим обновить из предложения from. (Обратите внимание, что это T-SQL, а не стандартный способ ANSI для совместного использования нескольких отношений в представлении.)
    1. Сначала мы самостоятельно присоединяемся к SessionBoundary равенством на UserGuid и тем, что являемся соседними границами на основе SessionNumber. Если бы у пользователя A было 2 сеанса, было бы 3 SessionNumber s 1, 2 и 3. Это объединение привело бы к (Low, High) парам (1, 2) и (2, 3). Теперь для каждого UserGuid у нас есть нижняя и верхняя граница каждого сеанса. Верхняя граница последнего сеанса - «конец времени».
    2. Затем мы присоединяемся к таблице, которую хотим обновить, Sessions Условие соединения состоит в том, что UserGuid равно, а дата строки в Sessions находится в пределах диапазона, определенного [LowBound, HighBound). Помните, что Границы - это где сессии начинаются . Таким образом, тест состоит в том, что LowBound <= Sessions. "Date" <HighBound. </li>
1 голос
/ 01 сентября 2009

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

0 голосов
/ 01 сентября 2009

Это выглядит правильно?

UPDATE T Set SessionGuid = 
    (Select Min(UserGuid) FROM [mytable] 
     Where IPAddress=T.IPAddress 
       And Date = (Select Min(Date) From MyTable
                   Where IPAddress = T.IPAddress
                       And DateDiff(minute, Date, T.Date) 
                              Between 0 and 30)) 
FROM [mytable] T
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...