Есть ли функция SQL, чтобы проверить, все ли между двумя записями совпадает?

#sql #ssms

#sql #ssms

Вопрос:

Я не могу использовать реальный пример, но вот пример некоторых данных, которые у меня могут быть:

ПРИМЕЧАНИЕ: Это уже упорядочено по метке времени, с самой старой строкой в первой (верхней) строке и самой новой строкой в последней (нижней) строке.

  ------------ --------------------- ---------------- ------------- 
| Product ID |       Status        | Days in Status |    Team     |
 ------------ --------------------- ---------------- ------------- 
| 1a         | designing           |              4 | Engineering |
| 1a         | gathering materials |              6 | Engineering |
| 1a         | creating            |             20 | Engineering |
| 1a         | testing function    |              5 | QA          |
| 1a         | testing usability   |             10 | QA          |
| 1a         | designing           |              4 | Engineering |
| 1a         | recreating          |              3 | Engineering |
| 1a         | testing usability   |              3 | QA          |
| 1a         | testing function    |              1 | QA          |
| 1a         | testing             |              4 | QA          |
 ------------ --------------------- ---------------- ------------- 
  

В этом примере я хотел бы найти количество дней, в течение которых продукт 1a был с QA в последнее время (не общее количество дней, в течение которых он был с QA). Это было бы 3 1 4 . Я также хочу найти количество дней, в течение которых это было с разработкой в последнее время. Это было бы 4 3 = 7.

У кого-нибудь есть идея, как это сделать?

———— редактировать вот лучший пример:

 
 ------------ -------------- ----------------------- ---------------- ------------- 
| Product id |     date     |        status         | days in status |    team     |
 ------------ -------------- ----------------------- ---------------- ------------- 
| 1a         | Jan 1 2020   | designing             |              4 | engineering |
| 1a         | Jan 5 2020   | gathering materials   |              4 | engineering |
| 1a         | Jan 9 2020   | creating              |              2 | engineering |
| 1a         | Jan 11 2020  | testing functionality |              3 | QA          |
| 1a         | Jan 14 2020  | testing usability     |              5 | QA          |
| 1a         | Jan 19 2020  | gathering materials   |              1 | engineering |
| 1a         | Jan 20 2020  | creating              |              3 | engineering |
| 1a         | Jan 23 2020  | testing functionality |              1 | QA          |
| 1a         | Jan 24 2020  | testing usability     |              1 | QA          |
 ------------ -------------- ----------------------- ---------------- ------------- 
  

Я хочу получить количество дней, в течение которых 1a был последним с QA (1 1), и количество дней, в течение которых QA ожидал разработки непосредственно перед этим (1 3)

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

1. Пожалуйста, определите «совсем недавно». В ваших данных нет столбца, который определяет порядок.

2. о, извините за это. самая старая находится в первой строке, а самая новая — в последней строке

3. . . Нет такой вещи. Таблицы SQL неупорядочены.

4. Нет ни «первой строки», ни «окончательного raw». Таблицы базы данных не отсортированы по своей природе.

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

Ответ №1:

Если вам конкретно нужна последняя группа, вы можете использовать not exists :

 select sum(days_in_status)
from t
where  not exists (select 1
                  from t
                  where t2.status <> t.status and t2.timestamp > t.timestamp
                 );
  

Если вам нужна последняя группа контроля качества, я бы предложил:

 select t.*
from (select t.*,
             dense_rank() over (partition by status order by seqnum - seqnum_2) as ranking
      from (select t.*,
                   row_number() over (order by timestamp desc) as seqnum,
                   row_number() over (partition by status order by timestamp desc) as seqnum_2
            from t
           ) t
     ) t
where status = 'QA' and ranking = 1;
  

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

1. Спасибо за вашу помощь!

Ответ №2:

Теперь я знаю, как проводить сеансы в базе данных, поддерживающей функции OLAP, давайте попробуем это здесь снова.

Нам нужен новый идентификатор сеанса, больший, чем предыдущий, каждый раз, когда команда меняется с течением времени, а затем суммировать дни для наибольшего идентификатора сеанса, который мы получаем.

 WITH
-- your input, enriched by a timestamp ...
input(Product_ID,Status,Days_in_Status,Team,ts) AS (
          SELECT '1a','designing'          , 4,'Engineering',TIMESTAMP '2020-07-05 12:21:01'
UNION ALL SELECT '1a','gathering materials', 6,'Engineering',TIMESTAMP '2020-07-11 12:22:02'
UNION ALL SELECT '1a','creating'           ,20,'Engineering',TIMESTAMP '2020-07-31 12:23:03'
UNION ALL SELECT '1a','testing function'   , 5,'QA'         ,TIMESTAMP '2020-08-05 12:24:04'
UNION ALL SELECT '1a','testing usability'  ,10,'QA'         ,TIMESTAMP '2020-08-15 12:02:05'
UNION ALL SELECT '1a','designing'          , 4,'Engineering',TIMESTAMP '2020-08-19 12:03:06'
UNION ALL SELECT '1a','recreating'         , 3,'Engineering',TIMESTAMP '2020-08-22 12:04:07'
UNION ALL SELECT '1a','testing usability'  , 3,'QA'         ,TIMESTAMP '2020-08-25 12:05:08'
UNION ALL SELECT '1a','testing function'   , 1,'QA'         ,TIMESTAMP '2020-08-26 12:06:09'
UNION ALL SELECT '1a','testing'            , 4,'QA'         ,TIMESTAMP '2020-08-30 12:07:10'
)
-- end of your input. In the real query, replace the following comma with 'WITH'
,
-- A counter that is at 1 every time the team changes, else at 0
with_counter AS (
  SELECT
    *
  , CASE WHEN LAG(team) OVER(ORDER BY ts) <> team
    THEN 1
    ELSE 0
    END AS counter
  FROM input
)
,
-- a running sum of the counter of the query just above, as session id ...
with_session AS (
  SELECT
    *
  , SUM(counter) OVER(ORDER BY ts) AS sessionid
  FROM with_counter
)
-- finally, group by the session id, and grab the last (biggest) session id.
-- LIMIT 1 in certain databases, 
-- in SQL server, you go 'SELECT TOP 1' instead of 'SELECT'
--   and do without the final LIMIT 1 clause at the end.
SELECT
  sessionid
, SUM(days_in_status)
FROM with_session
WHERE team='QA' -- don't know if this filter is needed ...
GROUP BY
  sessionid
ORDER BY 1 DESC LIMIT 1;
-- out  sessionid | sum 
-- out ----------- -----
-- out          3 |   8