Сравнить один и тот же столбец в той же таблице

#sql #sql-server #sql-server-2008 #join

#sql #sql-сервер #sql-server-2008 #Присоединиться

Вопрос:

Мне нужна помощь в решении этой проблемы. У меня есть следующая таблица (dbo.Users), упорядоченная по убыванию по идентификатору:

 ID |  UserID | Status | Time   |
3     9200       2      2013-05-03
2     9200       1      2013-05-02
1     9200       1      2013-05-01
  

Я хочу проверить, имеют ли две верхние строки разные значения для столбца состояния, и если да, я хочу получить всю первую строку.
Как я могу этого добиться?

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

1. SQL Server 2008

2. Привет. Я думаю, что тема недостаточно ясна. Могу ли я предложить что-то другое? — «Как сравнить 2 верхние строки, возвращающие верхнюю, если есть несоответствия?» или «Как сравнить 2 верхние строки?»

Ответ №1:

Предполагая, что под «двумя верхними строками» вы подразумеваете упорядочение по убыванию идентификатора, тогда:

 select u.*
from (select top 1 u.*
      from dbo.Users u
      order by u.id desc
     ) u
where u.status <> (select top 1 u2.status
                   from dbo.Users u2
                   where u2.id < u.id
                   order by u2.id desc
                  );
  

Первый подзапрос получает верхнюю строку. Второй подзапрос определяет, равен ли статус статусу во второй строке.

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

1. Спасибо! это именно то, что я хотел. Если бы я хотел сравнить больше столбцов, отличных от Status , следуя той же логике, могу ли я просто добавить AND / OR после оператора WHERE ?

2. @Dias . . . Задайте другой вопрос с примерами данных и желаемыми результатами.

Ответ №2:

Один из способов сделать это — добавить вычисляемый row_number в соответствии с идентификатором ПОЛЬЗОВАТЕЛЯ

 SELECT ID
    ,Userid
    ,STATUS
    ,TIME
    ,ROW_Number() OVER (
        PARTITION BY UserID
        OVER BY TIME DESC
        ) AS rn
FROM TABLE
  

Номер строки разделяется идентификатором пользователя, поэтому номер строки будет перезапущен для каждого идентификатора пользователя. Он сортируется по ВРЕМЕНИ, но вы можете изменить это, если хотите. Если вы хотите отфильтровать это, вам нужно будет обернуть его во внешний запрос

 select * from (SELECT ID
    ,Userid
    ,STATUS
    ,TIME
    ,ROW_Number() OVER (
        PARTITION BY UserID
        ,STATUS OVER BY TIME DESC
        ) AS rn
FROM TABLE
)sub
where sub.rn = 1
  

Ответ №3:

Предполагая, что идентификатор уникален, вы можете использовать следующий код:

 WITH cte 
 AS (SELECT TOP 2 * 
     FROM   dbo.users 
     ORDER  BY id DESC) 
SELECT cte1.* 
FROM   cte cte1 
   INNER JOIN cte AS cte2 
           ON cte1.id > cte2.id 
WHERE  cte1.status != cte2.status 
  

Если у вас таблица большего размера, то это тоже будет быстрее по сравнению с другими запросами.