从 100,101,102 等行创建范围(100-106、107、111-119)

Create ranges (100-106, 107, 111-119) from rows of 100,101,102, etc

我有一个 table 完整的美国所有邮政编码。 您可能知道邮政编码不一定是一个接一个,所以对于密歇根州,我有这些邮政编码(只是一个示例):

48001,48002,48003,48004,48005,48006,48007,48009,48012,48014,48015,48017

我需要做的是得到一行,例如:

48001-48007,48009,48012,48014-48015,48017

您可以看到我正在将顺序的邮政编码合并到开始-结束范围内,如果邮政编码不在一个序列中,它就会单独存在。

我只会处理一部分邮政编码,不会处理整个美国。因此,假设我有一个 temp table,其中包含我要使用的邮政编码,我可以根据需要填充此 temp table。现在这个临时 table 有一个邮政编码字段,但它可以根据需要定义。

我可以使用临时 tables、游标或其他任何东西,这将在存储过程中完成。如果您想知道为什么,我们有销售代表,每个人都负责特定的邮政编码,我们需要打印出某些代表。当客户服务接到客户的电话时,他们可以快速查看打印的 sheet 并扫描以查看负责该拉链的销售代表。

所以打印出来的纸看起来像:

Jim Smith...........48001-48007,48009,48012,48014-48015,48017
Heather Jones...59014, 59017, 59018-59022  (completely fake numbers, just as an example)

我意识到纸已经过时了,我们可以使用网站或任何其他方法来完成此操作,但无论出于何种原因必须打印它,所以我正在尝试尽可能地压缩邮政编码印刷用途。

您可以尝试以下方法。

create table zipcodes(zcode int);

insert into zipcodes
 select *
   from (values(48001),(48002),(48003),(48004),(48005),(48006),(48007),(48009),(48012),(48014),(48015),(48017))t(x);


select case when count(*) >1 then 
             concat(min(zcode),'-',max(zcode)) 
            else concat(max(zcode),'')
        end as concat_zcodes
from (
        select zcode
               ,ROW_NUMBER() over(order by zcode asc)  as rnk
               ,zcode - ROW_NUMBER() over(order by zcode asc) as grp
          from zipcodes
     )x
group by x.grp

您想将同一客户的相邻邮编组合在一起。我会将此作为差距和孤岛问题来解决,使用 lag() 和累积 sum() 来定义组:

select 
    customer_id,
    case when min(zip) = max(zip) 
        then concat(min(zip), '')
        else concat(min(zip),  '-', max(zip))
    end zip_range
from (
    select 
        customer_id,
        zip,
        sum(case when zip = lag_zip + 1 then 0 else 1 end) 
            over(partition by customer_id order by zip) grp
    from (
        select
            customer_id,
            zip,
            lag(zip) over(partition by customer_id order by zip) lag_zip
        from mytable t
    ) t
) t
group by customer_id, grp

Demo on DB Fiddle:

customer_id | zip_range  
----------: | :----------
          1 | 48001-48007
          1 | 48009      
          1 | 48012      
          1 | 48014-48015
          1 | 48017      

如果您有一列包含州和邮政编码,那么这是一个间隙和岛屿问题。对于各个范围:

select state,
       (case when min(zip_code) = max(zip_code)
             then min(zip_code)
             else concat(min(zip_code), '-', max(zip_code)
        end) as zips
from (select t.*,
             convert(int, zip_code) - row_number() over (partition by state order by zip_code) as grp
      from t
     ) t
group by state, grp;

为了您的最终结果,再次汇总:

select state, string_agg(zip_code, ',') 
from (select state,
             (case when min(zip_code) = max(zip_code)
                   then min(zip_code)
                   else concat(min(zip_code), '-', max(zip_code)
              end) as zips
      from (select t.*,
                   convert(int, zip_code) - row_number() over (partition by state order by zip_code) as grp
            from t
           ) t
      group by state, grp
     ) sg
group by state;

在旧版本中,您需要使用 XML hack 进行最终聚合。