Обрабатывайте NULL как максимально возможное значение - PullRequest
0 голосов
/ 05 октября 2018

Я хочу получить строку с максимальным номером транзакции, сгруппированную на основе Code.

CREATE TABLE SaleOrder
(
    TransactionNo Int,
    SaleOrderDate DATE,
    Code VARCHAR(25),
    Quantity INT,
    TotalAmount Numeric(18,2),
    Remarks VARCHAR(25)
)

INSERT INTO SaleOrder VALUES (NULL, '2018-10-01', 'SO-001-OCT-18',  6, 2500, 'Hello');
INSERT INTO SaleOrder VALUES (1,    '2018-10-01', 'SO-001-OCT-18',  8, 2600, 'Hello');
INSERT INTO SaleOrder VALUES (2,    '2018-10-01', 'SO-001-OCT-18', 12, 3400, 'Hello');
INSERT INTO SaleOrder VALUES (3,    '2018-10-01', 'SO-001-OCT-18',  9, 2900, 'Hello');
INSERT INTO SaleOrder VALUES (4,    '2018-10-01', 'SO-001-OCT-18',  2,  900, 'Hello');
INSERT INTO SaleOrder VALUES (NULL, '2018-10-01', 'SO-002-OCT-18',  6, 2500, 'Hello');
INSERT INTO SaleOrder VALUES (NULL, '2018-10-01', 'SO-003-OCT-18',  6, 2500, 'Hello');
INSERT INTO SaleOrder VALUES (0,    '2018-10-01', 'SO-004-OCT-18',  6, 2500, 'Hello');


SELECT * FROM SaleOrder O
WHERE TransactionNo  = (SELECT MAX(ISNULL(TransactionNo, 1)) FROM SaleOrder GROUP BY Code)

Здесь, когда TransactionNo равен NULL, он не возвращает никаких записей против него, хотя должен также возвращать и эту запись.

Ответы [ 6 ]

0 голосов
/ 05 октября 2018

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

CREATE TABLE #SaleOrder
(
    TransactionNo Int,
    #SaleOrderDate DATE,
    Code VARCHAR(25),
    Quantity INT,
    TotalAmount Numeric(18,2),
    Remarks VARCHAR(25)
)

INSERT INTO #SaleOrder VALUES (NULL, '2018-10-01', 'SO-001-OCT-18', 6, '2500', 'Hello');
INSERT INTO #SaleOrder VALUES (1, '2018-10-01', 'SO-001-OCT-18', 8, '2600', 'Hello');
INSERT INTO #SaleOrder VALUES (2, '2018-10-01', 'SO-001-OCT-18', 12, '3400', 'Hello');
INSERT INTO #SaleOrder VALUES (3, '2018-10-01', 'SO-001-OCT-18', 9, '2900', 'Hello');
INSERT INTO #SaleOrder VALUES (4, '2018-10-01', 'SO-001-OCT-18', 2, '900', 'Hello');
INSERT INTO #SaleOrder VALUES (NULL, '2018-10-01', 'SO-002-OCT-18', 6, '2500', 'Hello');
INSERT INTO #SaleOrder VALUES (NULL, '2018-10-01', 'SO-003-OCT-18', 6, '2500', 'Hello');
INSERT INTO #SaleOrder VALUES (0, '2018-10-01', 'SO-004-OCT-18', 6, '2500', 'Hello');

-- final select
SELECT top 1 -- optional, if you want to return 1 record
    Code,
    sum(Quantity) as totalQuantity, 
    sum(TotalAmount) as totallAmount, 
    count(1) as totalOrdersPerCode
FROM #SaleOrder O
group by Code
order by count(1) desc  

-- drop temp table
drop table #SaleOrder
0 голосов
/ 05 октября 2018

Попробуйте:

select TransactionNo,SaleOrderDate,Code,Quantity,TotalAmount,Remarks from (
    select TransactionNo,SaleOrderDate,Code,Quantity,TotalAmount,Remarks, 
           row_number() over (partition by code order by transactionno desc) rn 
    from (
        select TransactionNo,SaleOrderDate,Code,Quantity,TotalAmount,Remarks,
               coalesce(transactionno, count(*) over (partition by code) + 1) transactionno2
        from SaleOrder
    ) a
) a where rn = 1

Объяснение:

С помощью этой строки coalesce(transactionno, count(*) over (partition by code) + 1) transactionno2 я назначаю наибольшее значение для группы (разделенной на code), где этоноль. Но имейте в виду, , когда у вас есть два NULL s, строки будут связаны в этом случае, и это будет недетерминированный .

0 голосов
/ 05 октября 2018

Нет абсолютно никаких оснований для рассматривать NULL как максимально возможное значение .Вы всегда можете воспользоваться трюком ROW_NUMBER:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Code ORDER BY TransactionNo DESC) AS RN
    FROM SaleOrder
)
SELECT * FROM cte
WHERE RN = 1

Результат:

| TransactionNo | SaleOrderDate | Code          | Quantity | TotalAmount | Remarks | RN |
|---------------|---------------|---------------|----------|-------------|---------|----|
| 4             | 2018-10-01    | SO-001-OCT-18 | 2        | 900.00      | Hello   | 1  |
| NULL          | 2018-10-01    | SO-002-OCT-18 | 6        | 2500.00     | Hello   | 1  |
| NULL          | 2018-10-01    | SO-003-OCT-18 | 6        | 2500.00     | Hello   | 1  |
| 0             | 2018-10-01    | SO-004-OCT-18 | 6        | 2500.00     | Hello   | 1  |
0 голосов
/ 05 октября 2018

Я думаю, что эта ISNULL проверка должна решить вашу проблему, и замена = на IN подзапрос может вернуть несколько записей

WHERE ISNULL(TransactionNo, 1) IN
0 голосов
/ 05 октября 2018

когда вы используете = выберите в вашем предложении where, это совершенно неправильно, потому что это возможно, у вас есть несколько записей, поэтому вы должны изменить свой код следующим образом:

SELECT MAX(ISNULL(TransactionNo, 1)),code FROM SaleOrder O
 GROUP BY Code

, но если вы хотите вернуть толькоодна запись, которую вы можете использовать так:

SELECT * FROM SaleOrder O
WHERE TransactionNo  = (SELECT TOP 1 MAX(ISNULL(NULL, 1)) FROM SaleOrder GROUP BY Code)
0 голосов
/ 05 октября 2018

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

DECLARE @TransactionNo int

SELECT TOP 1 @TransactionNo = MAX(ISNULL(TransactionNo, 1)) FROM SaleOrder GROUP BY Code -- (OR) Logic here

SELECT * FROM SaleOrder O
WHERE TransactionNo  = @TransactionNo
...