【问题标题】:Select principal non-null (phone) numbers among several fields in SQL在 SQL 的多个字段中选择主要的非空(电话)号码
【发布时间】:2022-01-18 20:55:46
【问题描述】:

我目前的问题与电话号码有关,即使它可能适用于许多其他情况,我发现电话号码更明确,所以我们开始吧:

我有一个 Postgresql 表,其中有几个字段对应于客户可能提供的电话号码。即,我有phone_personalphone_professionalmobile_phone_personalmobile_phone_professional(这些字段是从我无权访问的网站填写的)。

一家外部公司要求我检索每个客户的两个主要电话号码(下面我称他们为 phone_1 和 phone_2)。

我想我可以通过明确使用 casecoalesce 来解决一些问题,以便:

  • 至少检索一个电话号码为phone_1(当然所有号码都为空)
  • 不要检索两个相同的电话号码(如果四个字段中只提供一个电话号码,只检索这个作为phone_1,空作为phone_2)
select coalesce(phone_personal, phone_professional, mobile_phone_personal, mobile_phone_professional)
       as phone_1
     , case when coalesce(phone_personal, phone_professional) is null
            then case when mobile_phone_personal is null
                      then null --in that case mobile_phone_professional is taken as phone_1 already
                      else mobile_phone_professional -- as mobile_phone_personal is taken as phone_1 already
                      end
            else case when phone_personal is null -- in that case phone_professional is phone_1
                      then coalesce (mobile_phone_personal, mobile_phone_professional)
                      else coalesce (phone_professional, mobile_phone_personal, mobile_phone_professional)
                      end 
            end 
       as phone_2

这看起来很笨拙,我很确定这是低效的。充其量只是丑陋。

我相信这是一个非常标准的问题,有没有人有改进这个查询的想法?

【问题讨论】:

  • 考虑使用正确的规范化数据会有多简单; PhoneNumbers 表格,每个数字 1 行,一列指示其优先级。
  • 嗯,这可能是对的。不过,我没有对源数据库的写入权限(当然,这不会丢弃您的评论)。
  • 你是对的,查询很笨拙,可能效率低下。然而,这是非常糟糕的设计决策的功能。但是,考虑到这种设计,你所拥有的就是尽可能好。仅显示您使用 非规范化 数据时遇到的复杂性。
  • 我在这里缺少一些东西。包含所有电话号码的表格如何更加规范化?我应该为每种电话号码类型提供一个表格吗?或者我应该有一个PhoneNumbers 表,其中有一列是电话号码,另一列表示其类型(加上另一列表示它所指的用户的ID,我猜)?但在那种情况下,我最终会采用 Entity-Value-Attribute 设计,我认为应该尽可能避免这种设计?

标签: sql postgresql algorithm


【解决方案1】:

假设你有:

u: postgres db: daf # select * from client;                                                                                                                                                                        
 id | cid |     p1     |     p2     |     p3     |     p4                                                                                                                                                          
----+-----+------------+------------+------------+------------                                                                                                                                                     
  1 |   1 | 1140751234 | [null]     | 1140751203 | [null]                                                                                                                                                          
  2 |   2 | 1140751235 | [null]     | 1140751204 | [null]                                                                                                                                                          
  3 |   3 | [null]     | 1140751235 | 1140751204 | [null]                                                                                                                                                          
  4 |   7 | 1140751206 | [null]     | [null]     | 1140751236                                                                                                                                                      
(4 rows)  

尝试翻转信息:

select * from (
select cid, p1 from client where cid = 1 union 
select cid, p2 from client where cid = 1 union 
select cid, p3 from client where cid = 1 union 
select cid, p4 from client where cid = 1 
) as tmp
where p1 is not null
limit 2;                                                                 

别忘了索引:

create index idx_client_cid on client (cid);

基于表格:

create table client ( id serial, cid int not null, p1 varchar, p2 varchar, p3 varchar, p4 varchar);

【讨论】:

  • 我想我明白你的意思,但这需要在之后再次将数据重写回柱状形式。此外,我希望检索所有客户的信息。我可能会用分区解决一些问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
  • 2018-06-24
  • 2011-10-25
相关资源
最近更新 更多