查找基于三个标准,后备值为两个

时间:2017-12-19 22:07:12

标签: sql postgresql

我有不同国家/地区的项目数据。每个项目都有一个devlevel,一个sector和一个subsector,例如(简化):

 pid  |                  sector                  |      subsector       | devlevel
------+------------------------------------------+----------------------+----------
  612 | Transport                                | Airports & Logistics | EM
 1473 | Information & Communication Technologies | Broadband            | RoW
 1424 | Other                                    | Other                | RoW
 1476 | Transport                                | Urban Highways       | RoW
 1443 | Water                                    | Water Supply         | EM

根据这三个特征的组合,每个项目都有一定的efficiency。目前,我已经构建了这样的查找表:

  sector   |     subsector      | devlevel | efficiency
-----------+--------------------+----------+------------
 Transport | (null)             | EM       |      16000
 Transport | (null)             | RoW      |       9600
 Water     | (null)             | EM       |      16000
 Water     | (null)             | RoW      |       9600
 Energy    | Generation — Hydro | EM       |      16000
 Energy    | Generation — Hydro | RoW      |       9600
 Energy    | (null)             | EM       |      11200
 Energy    | (null)             | RoW      |       6720
 (null)    | (null)             | EM       |       8000
 (null)    | (null)             | RoW      |       8000

逻辑是:如果项目有sectorsubsector匹配,请使用与其efficiency对应的devlevel。如果它与sector匹配但不是subsector,请使用与efficiencydevlevel subsector对应的NULL。如果sector上根本没有匹配,请使用efficiency sectorsubsector NULL的值。

我很难实现查询相关efficiency的查询。我的最新尝试如下。它尝试在初始子查询中基于sector缩小可能的查找值,然后在后续(父)子查询中根据subsector进一步缩小它们,然后将精简的查找表连接到使用devlevel上的匹配项目数据。但我收到此错误消息:

ERROR:  invalid reference to FROM-clause entry for table "p"
LINE 26:                 SELECT 1 FROM devlookup d1 WHERE p.sector = ...
                                                          ^
HINT:  There is an entry for table "p", but it cannot be referenced from this part of the query.
SQL state: 42P01
Character: 4079

非常感谢指针。

查询

WITH devlookup (id, sector, subsector, devlevel, efficiency)
AS (VALUES
    (1, 'Transport', NULL, 'EM', 16000),
    (2, 'Transport', NULL, 'RoW', 9600),
    (3, 'Water', NULL, 'EM', 16000),
    (4, 'Water', NULL, 'RoW', 9600),
    (5, 'Energy', 'Generation — Hydro', 'EM', 16000),
    (6, 'Energy', 'Generation — Hydro', 'RoW', 9600),
    (7, 'Energy', NULL, 'EM', 11200),
    (8, 'Energy', NULL, 'RoW', 6720),
    (9, NULL, NULL, 'EM', 8000),
    (10, NULL, NULL, 'RoW', 8000)
),
EMcountries AS (VALUES ('United Arab Emirates'), ('Afghanistan'), ('Antigua and Barbuda'), ('Anguilla'), ('Armenia'), ('Netherlands Antilles'), ('Angola'), ('Antarctica'), ('Argentina'), ('American Samoa'), ('Aruba'), ('Azerbaijan'), ('Barbados'), ('Bangladesh'), ('Burkina'), ('Bahrain'), ('Burundi'), ('Benin'), ('Brunei'), ('Bolivia'), ('Brazil'), ('Bahamas'), ('Bhutan'), ('Bouvet Island'), ('Botswana'), ('Belarus'), ('Belize'), ('Cocos (Keeling) Islands'), ('Congo {Democratic Rep}'), ('Central African Republic'), ('Congo'), ('Ivory Coast'), ('Cook Islands'), ('Chile'), ('Cameroon'), ('China'), ('Colombia'), ('Costa Rica'), ('Cuba'), ('Cape Verde'), ('Christmas Island'), ('Djibouti'), ('Dominica'), ('Dominican Republic'), ('Algeria'), ('Ecuador'), ('Egypt'), ('Western Sahara'), ('Eritrea'), ('Ethiopia'), ('Fiji'), ('Falkland Islands (Malvinas)'), ('Micronesia), (Federated States of'), ('Gabon'), ('Grenada'), ('Georgia'), ('French Guiana'), ('Ghana'), ('Gambia'), ('Guinea'), ('Guadeloupe'), ('Equatorial Guinea'), ('South Georgia and the South Sandwich Islands'), ('Guatemala'), ('Guam'), ('Guinea-Bissau'), ('Guyana'), ('Heard Island and McDonald Islands'), ('Honduras'), ('Haiti'), ('Indonesia'), ('India'), ('British Indian Ocean Territory'), ('Iraq'), ('Iran'), ('Jamaica'), ('Jordan'), ('Kenya'), ('Kyrgyzstan'), ('Cambodia'), ('Kiribati'), ('Comoros'), ('Saint Kitts and Nevis'), ('Korea), (Democratic People''s Republic of'), ('Kuwait'), ('Cayman Islands'), ('Kazakhstan'), ('Lao People''s Democratic Republic'), ('Lebanon'), ('St Lucia'), ('Sri Lanka'), ('Liberia'), ('Lesotho'), ('Libya'), ('Morocco'), ('Madagascar'), ('Marshall Islands'), ('Mali'), ('Myanmar), ({Burma}'), ('Mongolia'), ('Northern Mariana Islands'), ('Martinique'), ('Mauritania'), ('Montserrat'), ('Mauritius'), ('Maldives'), ('Malawi'), ('Mexico'), ('Malaysia'), ('Mozambique'), ('Namibia'), ('New Caledonia'), ('Niger'), ('Norfolk Island'), ('Nigeria'), ('Nicaragua'), ('Nepal'), ('Nauru'), ('Niue'), ('Oman'), ('Panama'), ('Peru'), ('French Polynesia'), ('Papua New Guinea'), ('Philippines'), ('Pakistan'), ('Pitcairn Islands'), ('Puerto Rico'), ('Palestinian Territory'), ('Palau'), ('Paraguay'), ('Qatar'), ('Reunion'), ('Rwanda'), ('Saudi Arabia'), ('Solomon Islands'), ('Seychelles'), ('South Sudan'), ('Sudan'), ('Saint Helena'), ('Sierra Leone'), ('Senegal'), ('Somalia'), ('Suriname'), ('Sao Tome & Principe'), ('El Salvador'), ('Syria'), ('Swaziland'), ('Turks and Caicos Islands'), ('Chad'), ('French Southern Territories'), ('Togo'), ('Thailand'), ('Tajikistan'), ('Tokelau'), ('Turkmenistan'), ('Tunisia'), ('Tonga'), ('Timor-Leste'), ('Trinidad & Tobago'), ('Tuvalu'), ('Tanzania'), ('Ukraine'), ('Uganda'), ('United States Minor Outlying Islands'), ('Uruguay'), ('Uzbekistan'), ('Saint Vincent and the Grenadines'), ('Venezuela'), ('Virgin Islands), (British'), ('Virgin Islands), (U.S.'), ('Vietnam'), ('Vanuatu'), ('Wallis and Futuna'), ('Samoa'), ('Yemen'), ('Mayotte'), ('South Africa'), ('Zambia'), ('Zimbabwe'), ('Saint Barthelemy'), ('Saint Martin')),
projectinfo AS (
    SELECT p.pid, p.country, p.projectname, p.sector, p.subsector,
        (CASE WHEN p.country IN (SELECT * FROM EMcountries) THEN 'EM' ELSE 'RoW' END) AS devlevel
    FROM exp_projects p
    )
SELECT p.pid, p.country, p.projectname, p.sector, p.subsector, p.devlevel, d.sector devsector, d.subsector devsubsector, d.efficiency
FROM projectinfo p 
LEFT OUTER JOIN (
    SELECT * FROM (
        SELECT * FROM devlookup WHERE id IN (
            CASE WHEN EXISTS (
                SELECT 1 FROM devlookup d1 WHERE p.sector = d1.sector
                )
            THEN (SELECT id FROM devlookup d1 WHERE d1.sector = p.sector)
            ELSE (SELECT id FROM devlookup d1 WHERE d1.sector IS NULL)
            END
        ) 
    ) AS devlookup_matching_sector
    WHERE id IN (
        CASE WHEN EXISTS (
            SELECT 1 FROM devlookup_matching_sector dms WHERE dms.subsector = p.subsector
            )
        THEN (SELECT id FROM devlookup_matching_sector dms WHERE dms.subsector = p.subsector)
        ELSE (SELECT id FROM devlookup_matching_sector dms WHERE dms.subsector IS NULL)
        END
    )
) devlookup_matching_sector_subsector
ON (devlookup_matching_sector_subsector.devlevel = p.devlevel)
WHERE p.country IN ('Australia', 'Afghanistan', 'Brazil')
ORDER BY pid ASC;

1 个答案:

答案 0 :(得分:0)

我还没有在这里修改您的主查询,只是演示了一种机制来选择最适用的特定效率:

SELECT
  p.*,
  COALESCE(mostspecific.efficiency, midspecific.efficiency, leastspecific.efficiency) as best_e
FROM
  Project p
  LEFT JOIN
  Efficiency mostspecific
  ON
    p.devlevel = mostspecific.devlevel AND
    p.sector = mostspecific.sector AND
    p.subsector = mostspecific.subsector

  LEFT JOIN
  Efficiency midspecific
  ON
    p.devlevel = midspecific.devlevel AND
    p.sector = midspecific.sector AND
     midspecific.subsector IS NULL

  LEFT JOIN
  Efficiency leastspecific
  ON
    p.devlevel = leastspecific.devlevel AND
    leastspecific.sector IS NULL AND
    leastspecific.subsector IS NULL

逻辑起作用,因为JOIN会在匹配方面有所不同。最小的特定应该始终匹配,med应该多次,最多,几次。 Coalesce从左到右选择第一个非空值,因此通过将效率按最有可能失败的顺序(为空)设置为最少意味着应该选择最相关的非空值