Найти максимальную дату для предметов с одинаковыми именами - PullRequest
1 голос
/ 29 октября 2019

Я пытаюсь найти отдельный список номеров заказов из базы данных. База данных будет размещена примерно так:

orderNumber    customer      createDate
---------------------------------------
001            123            2019-01-01
002            123            2019-01-23
003            456            2019-03-12
003R1          456            2019-03-22
004            456            2019-04-25
005            789            2019-05-21
005A1          789            2019-06-30
005R1          789            2019-07-12

R1 будет возвратом заказа, а A1 будет корректировкой для этого заказа.

Набор результатов, который я ищуfor - это список отдельных номеров заказов, который содержит только самую последнюю версию этого номера заказа. Пример:

Results
orderNumber    customer       CreateDate
----------------------------------------
001            123            2019-01-01
002            123            2019-01-23
003R1          456            2019-03-22
004            456            2019-04-25
005R1          789            2019-07-12

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

select customer, orderNumber, createDate
from (select customer
        ,orderNumber
        ,createDate
        ,ROW_NUMBER() over(partition by customer order by createDate desc) as RowNum
      from orders) as T
where RowNum = 1

Результатыэтого запроса будет выглядеть так:

orderNumber    customer      createDate
---------------------------------------
002            123            2019-01-23
003R1          456            2019-03-22
005R1          789            2019-07-12

Есть ли способ получить каждый номер заказа вместе только с самой последней версией "дубликата" номера заказа?

Ответы [ 2 ]

1 голос
/ 29 октября 2019

Вы почти получили это. Вам нужно разделить по нормализованному порядку номеров с убранным флагом. Здесь я использую left и substring, но вы должны использовать более надежное сопоставление с образцом, чтобы получить первые цифры.

select
  left(orderNumber, 3) as cleanOrderNumber,
  substring(orderNumber, 4, 5) as flag,
  customer,
  createDate,
  row_number() over (partition by left(orderNumber, 3) order by createDate desc) as RowNum
from orders;

cleanOrderNumber    flag    customer    createDate              RowNum
001                         123         01/01/2019 00:00:00     1
002                         123         23/01/2019 00:00:00     1
003                 R1      456         22/03/2019 00:00:00     1
003                         456         12/03/2019 00:00:00     2
004                         456         25/04/2019 00:00:00     1
005                 R1      789         12/07/2019 00:00:00     1
005                 A1      789         30/06/2019 00:00:00     2
005                         789         21/05/2019 00:00:00     3

Затем мы можем использовать это как CTE и получить первую строкудля каждого orderNumber.

with cleanOrders as (
select
  left(orderNumber, 3) as cleanOrderNumber,
  substring(orderNumber, 4, 5) as flag,
  customer,
  createDate,
  row_number() over (partition by left(orderNumber, 3) order by createDate desc) as RowNum
from orders
)
select *
from cleanOrders
where rowNum = 1;

cleanOrderNumber    flag    customer    createDate              RowNum
001                         123         01/01/2019 00:00:00     1
002                         123         23/01/2019 00:00:00     1
003                 R1      456         22/03/2019 00:00:00     1
004                         456         25/04/2019 00:00:00     1
005                 R1      789         12/07/2019 00:00:00     1

Обратите внимание, что если бы orderNumber и flag уже были разделены в таблице, это было бы проще и быстрее (их можно проиндексировать). Вы можете добавить новые столбцы, заполнить их и оставить orderNumber в качестве устаревшего.

0 голосов
/ 29 октября 2019

У меня это работает следующим образом. Это для DDL и примеров данных.

CREATE TABLE orders
    ([orderNumber] varchar(5), [customer] int, [createDate] datetime)
;

INSERT INTO orders
    ([orderNumber], [customer], [createDate])
VALUES
    ('001', 123, '2019-01-01 00:00:00'),
    ('002', 123, '2019-01-23 00:00:00'),
    ('003', 456, '2019-03-12 00:00:00'),
    ('003R1', 456, '2019-03-22 00:00:00'),
    ('004', 456, '2019-04-25 00:00:00'),
    ('005', 789, '2019-05-21 00:00:00'),
    ('005A1', 789, '2019-06-30 00:00:00'),
    ('005R1', 789, '2019-07-12 00:00:00')
;

И это фактический запрос:

WITH ordersCTE AS (
  SELECT *, PATINDEX('%[a-z]%', orderNumber) AS firstLetterPosition
  FROM orders AS O)
, ComputedOrderNumber AS (
  SELECT *, CAST(CASE firstLetterPosition
      WHEN 0 THEN orderNumber
      ELSE LEFT(orderNumber, firstLetterPosition -1)
    END AS INT) as actualOrderNumber
  FROM ordersCTE)
, Ordered AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY actualOrderNumber ORDER BY createDate DESC) AS RN
  FROM ComputedOrderNumber
  )
SELECT *
FROM Ordered
WHERE RN = 1

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

Но я бы настоятельно рекомендовал иметь соответствующий столбец для хранения корня orderNumber, вычисление которого каждый раз будет очень дорогим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...