PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Интерполация между две стойности в една заявка

Това е грозен хак (базиран на злоупотреба с CTE;). Същността на това е, че

value1 * distance2 + value2 * distance1

Може чрез разделяне на разстояние1*разстояние2 да се пренапише на

value1/distance1 + value2/distance2

Така че продуктите (или подразделенията) могат да останат в своите редове. След сумирането, умножаването по (разстояние1*разстояние2) премащабира резултата до желания резултат. Обобщението към повече от двама съседи е оставено като упражнение за читателя.YMMV

DROP TABLE tmp.points;
CREATE TABLE tmp.points
    ( pname VARCHAR NOT NULL PRIMARY KEY
    , distance INTEGER NOT NULL
    , value INTEGER
    );

INSERT INTO tmp.points(pname, distance, value) VALUES
  ( 'A' , 1, 10 )
,  ( 'B' , 4, 20 )
,  ( 'C' , 10 , 1)
,  ( 'D' , 11 , 2)
  ;
WITH RECURSIVE twin AS (
    select 1::INTEGER AS zrank
    , p0.pname AS zname
    , p0.distance AS dist
    , p0.value AS val
    , p0.distance* p0.value AS prod
    , p0.value::float / p0.distance AS frac
    FROM tmp.points p0
    WHERE NOT EXISTS ( SELECT * FROM tmp.points px
        WHERE px.distance < p0.distance)
    UNION
    select 1+twin.zrank AS zrank
    , p1.pname AS zname
    , p1.distance AS dist
    , p1.value AS val
    , p1.distance* p1.value AS prod
    , p1.value::float / p1.distance AS frac
    FROM tmp.points p1, twin
    WHERE p1.distance > twin.dist
    AND NOT EXISTS ( SELECT * FROM tmp.points px
        WHERE px.distance > twin.dist
        AND px.distance < p1.distance
        )   
    )
-- SELECT * from twin ;
SELECT min(zname) AS name1, max(zname) AS name2
    , MIN(dist) * max(dist) *SUM(frac) / SUM(dist) AS score
    FROM twin
    WHERE zrank <=2
    ;

Резултатът:

CREATE TABLE
INSERT 0 4
 name1 | name2 | score 
-------+-------+-------
 A     | B     |    12

Актуализация:тази е малко по-чисто ... връзките все още не се обработват (има нужда от функция за прозорец или клауза LIMIT 1 във външната заявка за това)

WITH RECURSIVE twin AS (
    select 1::INTEGER AS zrank
    , p0.pname AS name1
    , p0.pname AS name2
    , p0.distance AS dist
    FROM tmp.points p0
    WHERE NOT EXISTS ( SELECT * FROM tmp.points px
        WHERE px.distance < p0.distance)
    UNION
    select 1+twin.zrank AS zrank
    , twin.name1 AS name1
    , p1.pname AS name2
    , p1.distance AS dist
    FROM tmp.points p1, twin
    WHERE p1.distance > twin.dist
    AND NOT EXISTS ( SELECT * FROM tmp.points px
        WHERE px.distance > twin.dist
        AND px.distance < p1.distance
        )
    )
SELECT twin.name1, twin.name2
    , (p1.distance * p2.value + p2.distance * p1.value) / (p1.distance+p2.distance)  AS score
    FROM twin
    JOIN tmp.points p1 ON (p1.pname = twin.name1)
    JOIN tmp.points p2 ON (p2.pname = twin.name2)
    WHERE twin.zrank =2
    ;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Грешка в типа оператор на вложен случай (postgres)

  2. Може ли NLTK да се използва в съхранена процедура на Postgres Python

  3. sqlalchemy не се изпълнява Коментар на схемата

  4. Време за изчакване на препоръчителни заключвания в postgresql

  5. Динамичен ORDER BY и ASC / DESC във функция plpgsql