Группировка по и внутреннее объединение с последними записями на основе метки времени

#sql-server

#sql-сервер

Вопрос:

У меня есть History таблица, как показано ниже:

 ID | GroupCode | Category | TimeStamp
--- ----------- ---------- -----------
1  | x         | shoes    | 2016-09-01
2  | y         | blach    | 2016-09-01
  

History таблица обновляется каждый месяц, и в таблицу вставляется одна запись для каждой GroupCode .

У меня также есть Current таблица, которая содержит последнюю позицию.

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

Мне нужно сравнить последнее Category с текущим Category и, если оно изменилось, отметить CategoryChanged его в Current таблице.

Current таблица:

 ID | GroupCode | Category | CategoryChanged
--- ----------- ---------- ----------------
1  | x         | shoes    | True       
2  | y         | blah     | False
  

Я пытался добиться этого с INNER JOIN помощью, но у меня возникли трудности INNER JOIN с последними записями месяца и года в History таблице, но безуспешно.

Комментарии:

1. можете ли вы опубликовать запрос, который вы пробовали?

Ответ №1:

 --get highest group code based on timestamp   
 ;with History
    as
    (select top 1 with ties groupcode,category
    from
    history
    order by 
    row_number() over (partition by group code order by timestamp desc) as rownum
    )

--now do a left join with current table
    select 
    ct.ID,
    ct.GroupCode,
    ct.Category,
    case when ct.category=ht.category or ht.category is null then 'False'
         else 'true'
    end as 'changed'
     from
    currenttable ct
    left join
    history ht
    on ht.groupcode=ct.groupcode
  

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

 update ct
set ct.category=
 case when ct.category=ht.category or ht.category is null then 'False'
             else 'true'
        end 
         from
        currenttable ct
        left join
        history ht
        on ht.groupcode=ct.groupcode
  

Комментарии:

1. Как мне обновить столбец CategoryChanged с помощью этого?

2. Я не думаю, что этот код будет работать для вас, CTE в первом запросе выбирает только одну запись, она выбирает самую новую запись для одной конкретной группы случайным образом — поэтому, если у вас есть несколько групп для проверки, это не сработает. Второй запрос на обновление пытается изменить категорию на ‘true’ или ‘false’

3. @AndrewDeighton: Cte предоставляет мне последнюю категорию для всех кодов групп на основе метки времени, а не случайным образом

4. запрос имеет проблемы с синтаксисом. не могли бы вы обновить запрос?

5. вы должны использовать вышеуказанное обновление вместо выбора после cte

Ответ №2:

если вы создаете CTE, в котором записи истории имеют rown_numbwer для каждого группового кода, упорядоченного по убыванию даты, то вас интересуют строки 1 И 2, ПОЭТОМУ ВЫ МОЖЕТЕ присоединиться к своему CTE в GroupCode и выбрать записи 1 и 2, вы можете увидеть, изменилась ли категория между строками 1 и 2

     ;WITH CTE AS (SELECT *, row_number() OVER (PARTITION BY GroupCode ORDER BY TimeStamp Desc) RN FROM History)
    SELECT 
            C1.ID, 
            C1.GroupCode, 
            C1.Category, 
            CASE WHEN C1.Category = C2.Category THEN 
                'false' 
            else 
                'true' 
            end AS CategoryChanged

                FROM CTE C1 
                        JOIN 
                            CTE C2 
                                ON C1.GroupCode = C2.GroupCode 
                                    AND C1.Rn=1 AND C2.RN = 2;
  

если у вас есть нулевые категории, вы можете избежать с помощью — КСТАТИ, вам нужно будет научиться обрабатывать нули так, как вы хотите их обрабатывать — вы не можете ожидать, что люди будут публиковать здесь, думая о NULLS, которые вы никогда не упоминали навсегда! И происходит, чтобы понять, что вы хотите с ними делать, если на то пошло

 ;WITH CTE AS (SELECT *, row_number() OVER (PARTITION BY GroupCode ORDER BY TimeStamp Desc) RN FROM History)
    SELECT 
            C1.ID, 
            C1.GroupCode, 
            C1.Category, 
            CASE WHEN C1.Category = C2.Category OR C1.Category IS NULL AND C2.Category IS NULL THEN 
                'false' 
            else 
                'true' 
            end AS CategoryChanged

                FROM CTE C1 
                        JOIN 
                            CTE C2 
                                ON C1.GroupCode = C2.GroupCode 
                                    AND C1.Rn=1 AND C2.RN = 2;
  

Комментарии:

1. Если категория равна нулю в обоих, это возвращает true?

2. вы здесь слишком требовательны, вы знаете, вы действительно не дали понять, что бы вы хотели сделать, если бы оба имени были «НУЛЕВЫМИ» (или даже если это могло произойти). Также вы лишь смутно упомянули, что ожидали, что произойдет какое-то обновление — детали этого пока никак не ясны.

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

4. @akd — все в порядке, извинения приняты, был раздражительным — я вижу, вы и здесь оказали помощь — я должен был это проверить!