检索最接近的上限值

时间:2013-12-12 15:18:55

标签: sql sql-server database

您好,并提前感谢您的时间。

我必须解决这个具体问题。 我有下面的邮票表

idStamp     idCustomer  uptoW       uptoD       price
----------- ----------- ----------- ----------- -----------
218         4           2200        690         205
218         4           1700        660         155        

我需要找到符合4个条件的单行(如果存在):      - idStamp      - idCustomer      - uptoW      - uptoD

我用过

SELECT Distinct(UptoW) FROM [mytable]
WHERE uptoW=(SELECT MIN(uptoW)
FROM [mytable]
WHERE uptoW >= 1600-1 AND idStamp = 218 AND idCustomer = 4)

它适用于3个标准      - idStamp      - idCustomer      - uptoW

但我无法弄清楚如何实施第四个匹配标准。

总结
使用以下参数(idStamp = 218,idCustomer = 4,宽度= 1600,深度= 640)
我希望找到价格为155的行 ...但是...
使用param(idStamp = 218,idCustomer = 4,Width = 1600,Depth = 670)
我希望找到价格为205的行 如果没有办法满足所有标准,我希望没有行。

- 编辑2013.12.13 -

idStamp     idCustomer  UptoW       UptoD       price      
----------- ----------- ----------- ----------- -----------
218         4           220         69          155        
218         4           170         100         205        
218         4           230         100         400        
218         4           180         90          345        
218         4           180         89          34         
218         4           179         90          32         
218         4           179         89          2343       

DECLARE @p_idStamp INT = 218
,@p_idCustomer INT = 4
,@UptoW INT = 160
,@UptoD INT = 89
,@UptoWmin int
,@UptoDmin int;

SELECT @UptoWmin = MIN(UptoW) FROM mytable<br>
WHERE UptoW =(SELECT MIN(UptoW) FROM mytable<br>
WHERE UptoW >= @UptoW-1 AND idStamp = 218 AND idCustomer = 4)<br>

SELECT @UptoDmin = MIN(UptoD) FROM mytable<br>
WHERE UptoD =(SELECT MIN(UptoD) FROM mytable<br>
WHERE UptoD >= @UptoD-1 AND idStamp = 218 AND idCustomer = 4)<br>

SELECT TOP(1) * FROM mytable<br>
WHERE UptoW >= @UptoWmin AND UptoD >= @UptoDmin<br>
ORDER BY UptoW, UptoD<br>

SELECT TOP(1) * FROM mytable<br>
WHERE UptoW >= @UptoWmin AND UptoD >= @UptoDmin<br>
ORDER BY UptoD, UptoW<br>

我可能找到了解决方案 如您所见,我首先搜索表中的确切最小值 然后我编写一个满足两个参数的查询。 我重复查询颠倒order by子句,因为结果可能不同。

让我知道是否可以采用更好的解决方案。

3 个答案:

答案 0 :(得分:1)

我相信一种做你想要的方法是按超过区域排序结果,然后取第一行。

类似的东西:

-- Test schema, based on S Koppenol answer:
CREATE TABLE stamps (
    [idStamp]    INT,
    [idCustomer] INT,
    [uptoW]      INT,
    [uptoD]      INT,
    [price]      MONEY
)

INSERT INTO stamps (
    [idStamp], [idCustomer], [uptoW], [uptoD], [price]
) VALUES
    (218, 4, 2200, 690, 205.0),
    (218, 4, 1700, 660, 155.0)
GO

-- Procedure to find the desired row:
CREATE PROCEDURE GetRow(
    @idStamp    INT,
    @idCustomer INT,
    @uptoW      INT,
    @uptoD      INT
) AS
BEGIN
    SELECT TOP 1
        T.idStamp,
        T.idCustomer,
        T.uptoW,
        T.uptoD,
        (T.uptoW * T.uptoD - @uptoW * @uptoD) AS DELTA_AREA
    FROM
        stamps T
    WHERE
        T.uptoW       >= @uptoW + 1
        AND T.uptoD   >= @uptoD + 1
        AND idStamp    = @idStamp
        AND idCustomer = @idCustomer
    ORDER BY
        DELTA_AREA
END
GO

-- Testing  
EXEC GetRow 218, 4, 1600, 640; 
EXEC GetRow 218, 4, 1700, 640;
EXEC GetRow 218, 4, 1600, 660;
EXEC GetRow 218, 4, 2200, 660;

测试结果:

idStamp     idCustomer  uptoW       uptoD       DELTA_AREA
----------- ----------- ----------- ----------- -----------
218         4           1700        660         98000

(1 row(s) affected)

idStamp     idCustomer  uptoW       uptoD       DELTA_AREA
----------- ----------- ----------- ----------- -----------
218         4           2200        690         430000

(1 row(s) affected)

idStamp     idCustomer  uptoW       uptoD       DELTA_AREA
----------- ----------- ----------- ----------- -----------
218         4           2200        690         462000

(1 row(s) affected)

idStamp     idCustomer  uptoW       uptoD       DELTA_AREA
----------- ----------- ----------- ----------- -----------

(0 row(s) affected)

这样你肯定会得到一条不仅在要求的限制范围内,而且还有最接近的记录。

答案 1 :(得分:0)

您可以将uptoD >= DESIRED_VALUE添加到验证中。

例如:

SELECT Distinct(UptoW) FROM [stamps]
WHERE uptoW=(SELECT MIN(uptoW)
FROM [stamps]
WHERE uptoW >= 1600-1 AND uptoD >= 640 AND idStamp = 218 AND idCustomer = 4);

这会给你:

UPTOW
1700

但你可以进一步简化并做:

SELECT MIN(uptoW) AS UPTOW
FROM [stamps]
WHERE uptoW >= 1600-1 
  AND uptoD >= 640 
  AND idStamp = 218 
  AND idCustomer = 4

sqlfiddle demo

答案 2 :(得分:0)

我并不完全确定所期望的最终结果,但我认为这将会很接近。这将为您提供符合所有条件的最低 uptoW (如果有)的记录。

DECLARE @p_idStamp INT = 218
,@p_idCustomer INT = 4
,@p_uptoW INT = 1600
,@p_uptoD INT = 640;

SELECT TOP 1 *
FROM mytable
WHERE idStamp = @p_idStamp
AND idCustomer = @p_idCustomer
AND uptoW > @p_uptoW
AND uptoD > @p_uptoD
ORDER BY uptoW ASC;