将NULL视为最大可能值

时间:2018-10-05 11:03:09

标签: sql sql-server null aggregate-functions

我想获得具有基于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 :(得分:3)

绝对没有理由将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  |

答案 1 :(得分:0)

当TransactionNo为NULL且查询返回无法分配给过滤器的多行

以下内容可能会帮助

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

请注意,这可以记录任何TransactionNo值为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

答案 2 :(得分:0)

在使用=时,在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)

答案 3 :(得分:0)

我认为此ISNULL检查应该可以解决您的问题,并用=子查询替换IN可以返回多个记录

WHERE ISNULL(TransactionNo, 1) IN

答案 4 :(得分:0)

尝试一下:

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时,在这种情况下,行将被绑在一起,并且会不确定性

答案 5 :(得分:0)

下面的代码将为您提供比您想要的信息更多的信息,您可以使用它,并在有任何疑问时添加一些注释。

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
相关问题