SQL - получить данные, где MAX номер <номер - PullRequest
3 голосов
/ 26 апреля 2019

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

---------------------------------------
CREATE TABLE Test (     
       [Rowid] INT NOT NULL
      ,[Agent_Name] VARCHAR NOT NULL
      ,[Type Login_Break] VARCHAR NOT NULL
      ,[Class] INT NOT NULL
  PRIMARY KEY (Rowid)
);

INSERT INTO Test 
    ([Rowid], [Agent_Name], [Type Login_Break],[Class]) 
VALUES 
    (7276541,'TrevorT','Login',162),
    (7276993,'TrevorT','Break',0),
    (7277421,'TrevorT','Break',0),
    (7278660,'TrevorT','Login',106),
    (7278754,'TrevorT','Login',162),
    (7279485,'TrevorT','Break',0),
    (7280372,'TrevorT','Login',69),
    (7280984,'TrevorT','Break',0),
    (7281135,'TrevorT','Login',162),
    (7282310,'TrevorT','Login',162),
    (7283716,'TrevorT','Break',0)
---------------------------------------------

Сначала я попытался использовать CTE, где MAX (RowID) <(RowID), однако, зашел в тупик.каждый раз. </p>

Исходный вывод:

enter image description here

Требуемый вывод:

enter image description here

Ответы [ 5 ]

3 голосов
/ 26 апреля 2019

Ах, вы можете попробовать что-то вроде этого:

with data as (
    select *, 
        case 
        when class = 0 then
          (
            select max(rowid) from test
            where class > 0 and rowid < a.rowid
          )
        else null
        end as newrowid
    from test a
)
select
    data.rowid, data.agent_name, data.[type login_break],
    case when data.class = 0 then test.class else data.class end as class
from data
left join test on data.newrowid = test.rowid;

Результат

rowid   agent_name  type login_break    class
7276541 TrevorT     Login               162
7276993 TrevorT     Break               162
7277421 TrevorT     Break               162
7278660 TrevorT     Login               106
7278754 TrevorT     Login               162
7279485 TrevorT     Break               162
7280372 TrevorT     Login               69
7280984 TrevorT     Break               69
7281135 TrevorT     Login               162
7282310 TrevorT     Login               162
7283716 TrevorT     Break               162

Пример: https://rextester.com/QITJ76405

Объяснение

  • Создание фиктивного набора данных с помощью теста
  • В этом фиктивном наборе данных добавьте столбец для случая, когда class = 0
  • Этот столбец будетмаксимальный идентификатор предыдущих строк
  • Таким образом, вы получите информацию о предыдущем классе до перерыва
  • Получите все данные из этого фиктивного набора данных и объедините его с оригиналом, где соответствует newrowidoriginal rowid
  • Если фиктивный набор данных имеет класс 0, замените его классом из оригинала
2 голосов
/ 26 апреля 2019

Может сделать это за один проход, если SQL Server имеет пользовательский агрегат :

Живой тест: https://www.db -fiddle.com / f / vXymxPPj3Ngmqoa9DqFc7S / 0

select *, 
    sum_with_reset(class, type_login_break = 'Login') over(order by row_id)
from test

Вывод:

| row_id  | agent_name | type_login_break | class | sum_with_reset |
| ------- | ---------- | ---------------- | ----- | -------------- |
| 7276541 | TrevorT    | Login            | 162   | 162            |
| 7276993 | TrevorT    | Break            | 0     | 162            |
| 7277421 | TrevorT    | Break            | 0     | 162            |
| 7278660 | TrevorT    | Login            | 106   | 106            |
| 7278754 | TrevorT    | Login            | 162   | 162            |
| 7279485 | TrevorT    | Break            | 0     | 162            |
| 7280372 | TrevorT    | Login            | 69    | 69             |
| 7280984 | TrevorT    | Break            | 0     | 69             |
| 7281135 | TrevorT    | Login            | 162   | 162            |
| 7282310 | TrevorT    | Login            | 162   | 162            |
| 7283716 | TrevorT    | Break            | 0     | 162            |

определение sum_with_reset:

create or replace function sum_reset_accum(
    _accumulated numeric, _current numeric, reset boolean
)
returns numeric as
$$
    select case when reset then
        _current
    else
        _current + _accumulated
    end    
$$ language sql;


create aggregate sum_with_reset(numeric, boolean)
(
    sfunc = sum_reset_accum,
    stype = numeric,
    initcond = 0
);
2 голосов
/ 26 апреля 2019

Это будет работать на SQL Server, используется синтаксис стандарта SQL

Скрипт SQL Server: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=9733051365513941f5057dc38c0b6356

Скрипт Postgres: https://www.db -fiddle.com / f /uxVcYPsw4tFCjpJtX3VrCh / 0

with a as 
(
  select
      *, 
      sum(case when type_login_break = 'Login' then 1 end) 
      over(order by row_id) as login_group
  from test
)
select 
    row_id, agent_name, type_login_break, 
    class, 
    sum(class) over(partition by login_group order by row_id)
from a;

Выход:

| row_id  | agent_name | type_login_break | class | sum |
| ------- | ---------- | ---------------- | ----- | --- |
| 7276541 | TrevorT    | Login            | 162   | 162 |
| 7276993 | TrevorT    | Break            | 0     | 162 |
| 7277421 | TrevorT    | Break            | 0     | 162 |
| 7278660 | TrevorT    | Login            | 106   | 106 |
| 7278754 | TrevorT    | Login            | 162   | 162 |
| 7279485 | TrevorT    | Break            | 0     | 162 |
| 7280372 | TrevorT    | Login            | 69    | 69  |
| 7280984 | TrevorT    | Break            | 0     | 69  |
| 7281135 | TrevorT    | Login            | 162   | 162 |
| 7282310 | TrevorT    | Login            | 162   | 162 |
| 7283716 | TrevorT    | Break            | 0     | 162 |
0 голосов
/ 26 апреля 2019

Немного сложно без полной схемы таблицы, но я бы предложил создать CTE с помощью функций RANK () или DENSE_RANK ().Тогда что-то вроде:

SELECT * FROM cte1 WHERE R = 1; 

Где R = новый столбец с использованием функции Rank.

0 голосов
/ 26 апреля 2019

Нет необходимости в CTE или в ранге, просто нужно просто выбрать оператор case:

 select  
         Rowid, 
         agent_name, 
case [type login_break] when 'login' then RowID else
         (select top 1 RowID from test where RowID < t.Rowid and BreakClass='Break' order by 
         rowid desc) end as Login_Break_Class
    from test t 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...