返回与搜索值最接近的值

时间:2016-11-16 14:30:20

标签: sql pdw-file-browser

enter code here我需要按类型配对车辆,然后按燃料消耗配对。燃料消耗可能不匹配,在这种情况下,最接近的选择。同一车辆不能用于配对多次。我所谈论的数据类型的例子如下:

create table #table1
(
vehicleid varchar(2),
typed varchar(5),
fuelconsumption int
)


create table #table2
(
vehicleid varchar(2),
typed varchar(5),
fuelconsumption int
)


INSERT INTO #table1 VALUES('x1','car',5);
INSERT INTO #table1 VALUES('x2','car',4);
INSERT INTO #table1 VALUES('x3','car',8);

INSERT INTO #table2 VALUES('b1','car',7);
INSERT INTO #table2 VALUES('b2','car',8);
INSERT INTO #table2 VALUES('b3','car',9);
INSERT INTO #table2 VALUES('b4','car',10);
INSERT INTO #table2 VALUES('b5','car',11);
INSERT INTO #table2 VALUES('b6','truck',15);
INSERT INTO #table2 VALUES('b7','truck',4);

将返回如下输出: enter image description here

1 个答案:

答案 0 :(得分:0)

虽然这可能不是一个完整的答案(仍在制定细节),但如果你从这开始,你将得到一个按升序排列的最佳匹配车辆ID列表:

    SELECT baseID = ibase.vehicleid,
           matchID = im.vehicleid,
           rowNum = ROW_NUMBER()
                    OVER (PARTITION BY ibase.vehicleid
                          ORDER BY ABS(ibase.fuelconsumption - im.fuelconsumption)) 
      FROM #table1 ibase
             INNER JOIN #table2 im ON ibase.typed = im.typed 

从这里你应该能够循环拾取"首先" " b"的实例车辆

完整答案(注意:我讨厌游标,但这有效):

DROP TABLE #results
CREATE TABLE #results ( vehicleid1 VARCHAR(2), vehicleid2 VARCHAR(2), diff INT, rownum INT )

INSERT INTO #results ( vehicleid1, vehicleid2, diff, rownum ) 
SELECT baseID = ibase.vehicleid,
       matchID = im.vehicleid,
       diff = ABS(ibase.fuelconsumption - im.fuelconsumption),
       rowNum = ROW_NUMBER()
                    OVER (
                        PARTITION BY ibase.vehicleid
                        ORDER BY ABS(ibase.fuelconsumption - im.fuelconsumption))
  FROM #table1 ibase
       INNER JOIN #table2 im ON ibase.typed = im.typed 

-- The cursor ensures we get the real best match so we do not accidentally
-- assign a best match which is a _better_ match for another vehicle
DECLARE CUR_ CURSOR FOR SELECT vehicleid1 FROM #results ORDER BY diff
DECLARE @id VARCHAR(2)

OPEN CUR_
FETCH CUR_ INTO @id
WHILE @@FETCH_STATUS = 0
BEGIN

    -- Remove all matches other than the BEST match
    DELETE r
      FROM #results r
     WHERE r.vehicleid1 = @id
       AND r.rownum <> (SELECT MIN(ir.rownum) FROM #results ir WHERE ir.vehicleid1 = @id)

    -- Remove all other matches which use the remaining matched vehicle 
    DELETE r
      FROM #results r
     WHERE r.vehicleid1 <> @id
       AND r.vehicleid2 = (SELECT ir.vehicleid2 FROM #results ir where ir.vehicleid1 = @id)

    FETCH CUR_ INTO @id
END
CLOSE CUR_
DEALLOCATE CUR_

SELECT * FROM #results

非光标解决方案:

DROP TABLE #results
CREATE TABLE #results ( vehicleid1 VARCHAR(2), vehicleid2 VARCHAR(2), diff INT, rownum INT )

INSERT INTO #results ( vehicleid1, vehicleid2, diff, rownum ) 
SELECT baseID = ibase.vehicleid,
       matchID = im.vehicleid,
       diff = ABS(ibase.fuelconsumption - im.fuelconsumption),
       rowNum = ROW_NUMBER()
                    OVER (
                        PARTITION BY ibase.vehicleid
                        ORDER BY ABS(ibase.fuelconsumption - im.fuelconsumption))
  FROM #table1 ibase
       INNER JOIN #table2 im ON ibase.typed = im.typed 

DECLARE @id VARCHAR(2)
WHILE EXISTS( SELECT vehicleid1 FROM #results GROUP BY vehicleid1 HAVING COUNT(*) > 1 )
BEGIN

    SELECT TOP 1 
           @id = r.vehicleid1
      FROM #results r
            INNER JOIN (SELECT i.vehicleid1 FROM #results i GROUP BY i.vehicleid1 HAVING COUNT(*) > 1) i
              ON r.vehicleid1 = i.vehicleid1
     ORDER BY r.diff

    -- Remove all matches other than the BEST match
    DELETE r
      FROM #results r
     WHERE r.vehicleid1 = @id
       AND r.rownum <> (SELECT MIN(ir.rownum) FROM #results ir WHERE ir.vehicleid1 = @id)

    -- Remove all other matches which use the remaining matched vehicle 
    DELETE r
      FROM #results r
     WHERE r.vehicleid1 <> @id
       AND r.vehicleid2 = (SELECT ir.vehicleid2 FROM #results ir where ir.vehicleid1 = @id)

END

SELECT * FROM #results