sql >> データベース >  >> RDS >> PostgreSQL

1つのクエリでの2つの値間の補間

    これは醜いハックです(悪用されたCTEに基づく;)。その核心はそれです

    value1 * distance2 + value2 * distance1
    

    distance1 * distance2で割ることにより、次のように書き換えることができます

    value1/distance1 + value2/distance2
    

    したがって、製品(または部門)は列の中にとどまることができます。合計後、(distance1 * distance2)を掛けると、結果が目的の出力に再スケーリングされます。 3人以上の隣人への一般化は、読者の練習問題として残されています。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. IISとSQLServerを同じマシンでホストできるのはいつですか。

    2. データベースのMySQLデータベースサイズを取得するにはどうすればよいですか?

    3. ML{.NET}はじめに

    4. MYSQL-LEFTJOINの行が存在しない場合にのみ選択します