【问题标题】:Convert SQL statement in SAS to POSTGRESQL将 SAS 中的 SQL 语句转换为 POSTGRESQL
【发布时间】:2016-03-21 16:23:40
【问题描述】:

如何让这个在 SAS 中工作的 SQL 代码在 POSTGRESQL 中工作。下面是在 SAS 中有效但在 POSTGRESQL 中无效的代码。

newname='Other';

if fullstate='Alaska' then equal_area_id='RAINIER';

if fullstate='Hawaii' then equal_area_id='SHASTA';

if fullstate='California' then equal_area_id='SHASTA'; 

if fullstate='California' and county in    (45 21 7 63 91 57 33 11 10143 47 99 77 67 109 9 5 17 61 115 113 55 97 95 3)   then equal_area_id='MENDOCINO';

以下脚本类型在 POSTGRESQL 中有效,但它仅将新字段标记为“TEMECULA”而不是“SHIPROCK”

UPDATE new_counties2

SET newname = CASE     
WHEN fullstate = 'Arizona' THEN 'TEMECULA' 

WHEN fullstate = 'Arizona' AND county IN ('1', '17', '5', '15', '7') THEN 'SHIPROCK' END
WHERE newname IN ('Other')

这将适用于整个国家,所以我需要以某种方式直接格式化。

【问题讨论】:

  • 这不是 SAS SQL - 它看起来确实像一个数据步骤。通常,您通过 Case 语句转换为 SQL。

标签: database postgresql postgis


【解决方案1】:

case 表达式中的条件顺序很重要。

假设有 3 个条件,

case when condition1 then 1
     when condition2 then 2
     when condition3 then 3
end

如果某行满足条件1,则不会评估条件2 和条件3。同样,如果条件1失败并且满足条件2,则不会检查条件3。

要获得所需的结果,请使用

CASE
WHEN fullstate = 'Arizona' AND county IN ('1', '17', '5', '15', '7') THEN 'SHIPROCK'
WHEN fullstate = 'Arizona' THEN 'TEMECULA'
END

【讨论】:

  • 如果我的列表中的条件顺序不同步,是否有更好的方法来填充“新名称”字段,或者 CASE 表达式是解决此问题的唯一方法
  • 你的意思是county IN ('1', '17', '5', '15', '7')中的县顺序吗?如果是这样,那没关系。
  • 您应该构建一个查找表,然后使用连接。在代码中保留这样的逻辑随着时间的推移很难维护并且容易出错。对于上述加利福尼亚案例,您也会遇到类似的错误。
  • 没有不是县的顺序。现在,当我运行关于 Arizona 的代码 sn-p 时,“newname”列仅填充“TEMECULA”而不是“SHIPROCK”,也许它与 WHERE 语句有关? @Reeza 我对 SQL 很陌生,不知道如何创建查找表,我想阅读一下,有什么建议吗?
  • 跟订单有关。执行时,如果州是亚利桑那州,则第一个 WHEN 语句为真,因此永远不会检查下一个语句。
【解决方案2】:

我们可以创建一些示例数据:

create table test (fullname varchar(20), county integer);
\copy test from stdin with delimiter ',';
Alaska,1
Arizona,2
California,5
California,6
\.

对于两种替代方法中的第一种,我们可以考虑嵌套 case 语句:

select county, fullname,
   case fullname
     when 'Alaska' then 'RAINIER'
     when 'Arizona' then 'SHASTA'
     when 'California' then case
          when county in (45, 21, 7, 63, 91, 57, 33, 11, 10143, 47, 99, 77, 67, 109, 9, 5, 17, 61, 115, 113, 55, 97, 95, 3) then 'MENDOCINO'
          else 'SHASTA' end
     else ''
     end as equal_area_id
from test 
order by county;

对于某些读者来说,这个逻辑可能更容易理解。其次,更接近于 datastep 代码,我们可以使用 plpgsql:

create or replace function equal_area_id(fullname varchar(20), county integer) returns varchar(10)
as $$
begin
    if fullname='Alaska' then return 'ALASKA';
    elsif fullname='Arizona' then return 'SHASTA';
    elsif fullname='California' and county in (45, 21, 7, 63, 91, 57, 33, 11, 10143, 47, 99, 77, 67, 109, 9, 5, 17, 61, 115, 113, 55, 97, 95, 3) then return 'MENDOCINO'; 
    elsif fullname='California' then return 'SHASTA';
    end if;
end;
$$ language plpgsql;

select county, fullname, equal_area_id(fullname,county)
from test
order by county;

这不像 SAS 数据步那样简洁,但更加模块化。两种方法都给出相同的输出:

 county |  fullname  | equal_area_id 
--------+------------+---------------
      1 | Alaska     | ALASKA
      2 | Arizona    | SHASTA
      5 | California | MENDOCINO
      6 | California | SHASTA
(4 rows)

【讨论】:

    【解决方案3】:

    您目前正在将规则硬编码到您的代码中。我建议构建一个表来保存这些值,然后改用连接。

    以某种方式在您的系统中创建一个将州和县映射到 eq​​ual_area_id 的表。

    State County Equal_area_id
    AZ  1 Temecula
    AZ  2 Temecula
    AZ  3 Shiprock
    NV  1 Vegas
    NV  2 Vegas
    CA  1 Shasta
    CA 45 Mendocino
    CA 21 Mendocino
    

    然后在 postgresql 中使用 join 而不是 case 语句。这样,如果您需要进行更新,您可以更新您的表格并且您的代码保持不变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-18
      • 1970-01-01
      • 2013-02-15
      • 2019-07-03
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多