【问题标题】:PostgreSQL : check if value is in 2 columns and remove it from one of themPostgreSQL:检查值是否在 2 列中并将其从其中之一中删除
【发布时间】:2021-12-19 12:57:00
【问题描述】:

我有两列 indtar 都包含数组。

 ind      tar
{10}      {10}
{6}       {5,6}
{4,5,6}   {5,6}
{5,6}     {5,6}
{7,8}     {11}
{11}      {5,6,7}
{11}      {8}
{9,10}    {6}

我想查找两个数组中是否存在一个值,如果是,我只想将其保留在列ind。例如,在第一行,我在两列中都有值 10。我只想在ind 列中得到这个值,并将tar 列留空。这是预期的结果:

 ind      tar      
{10}      
{6}       {5}
{4,5,6}   
{5,6}     
{7,8}     {11}
{11}      {5,6,7}
{11}      {8}
{9,10}    {6}

如何在 PostgreSQL 中做到这一点?

到目前为止,我只设法找到了公共元素,但我不知道如何继续将它们仅保留在 ind 列中并将它们从 tar 列中删除。

with t1 as (
select distinct ind, tar
from table_1
join table_2 using (id) 
limit 50
),
t2 as (
select ind & tar as common_el, ind , tar 
from t1
)
select *
from t2

结果如下:

   common_el   ind        tar
    {10}      {10}       {10}
    {6}       {6}       {5,6}
    {5,6}     {4,5,6}   {5,6}
    {5,6}     {5,6}     {5,6}

【问题讨论】:

    标签: sql arrays postgresql


    【解决方案1】:

    你可以这样做(fiddle):

    表创建:

    CREATE TABLE t(x INTEGER[], y INTEGER[]);
    

    填充表格:

    INSERT INTO t VALUES
    ('{10}',      '{10}'),
    ('{6}',       '{5,6}'),
    ('{4,5,6}',   '{5,6}'),
    ('{5,6}',     '{5,6}'),
    ('{7,8}',     '{11}'),
    ('{11}',      '{5,6,7}'),
    ('{11}',      '{8}'), 
    ('{9,10}',    '{6}'),
    
    --
    -- records below added for testing!
    --
    
    ('{11}',      '{5,8,10,11,133}'),  
    ('{9,10}',    '{4,5,6,8,9,10,11}'),
    ('{9,10}',    '{4,5,6,8,9,10,11}');
    

    标准数组,UNNEST + EXCEPT (fiddle):

    如果您不想或不能,请使用INTARRAY

    SELECT 
      t.x,
      ARRAY((SELECT UNNEST(t.y)) EXCEPT (SELECT UNNEST(t.x))) 
    FROM 
      t;
    

    结果:

    x   array
    {10}    {}
    {6} {5}
    {4,5,6} {}
    {5,6}   {}
    {7,8}   {11}
    {11}    {7,5,6}
    {11}    {8}
    {9,10}  {6}
    {11}    {8,10,133,5}
    {9,10}  {11,8,5,4,6}
    {9,10}  {11,8,5,4,6}
    

    等等 - 想要的结果!请参阅 here 以获得一个优秀的线程,其中包含许多解决此问题的方法以及讨论的密切相关问题!

    【讨论】:

      【解决方案2】:

      您使用的& 运算符来自intarray 模块,该模块还允许您使用- 将一个数组中的元素从另一个数组中删除。

      例如。

      select
          ind,
          tar,
          ind & tar as common_el,
          tar - (ind & tar) as  new_tar
      from
          table_1
      
      ind tar common_el new_tar
      {10} {10} {10} {}
      {6} {5,6} {6} {5}
      {4,5,6} {5,6} {5,6} {}
      {5,6} {5,6} {5,6} {}
      {7,8} {11} {} {11}
      {11} {5,6,7} {} {5,6,7}
      {11} {8} {} {8}
      {9,10} {6} {} {6}

      或更简单

      select
          ind,
          tar,
          ind & tar as common_el,
          tar - ind as  new_tar
      from
          table_1
      

      View working demo db fiddle here

      编辑 1:适用于非 intarray 模块用户。

      使用UNNEST 将数组转换为多行,这可以通过多种 sql 方法来解决,以识别一组元素不在另一组中的位置,例如。

      select
          ind,
          array(
              select t1.val from unnest(tar) t1(val)
              where t1.val not in (
                   select val from unnest(ind) i1(val)
              )
          ) as  new_tar
      from
          table_1
      
      ind new_tar
      {10} {}
      {6} {5}
      {4,5,6} {}
      {5,6} {}
      {7,8} {11}
      {11} {5,6,7}
      {11} {8}
      {9,10} {6}

      View working demo on db fiddle

      【讨论】:

        【解决方案3】:

        这也可以这样完成(下面的所有代码都可以在小提琴here上找到):

        CREATE OR REPLACE FUNCTION array_diff (array1 ANYARRAY, array2 ANYARRAY)
        RETURNS ANYARRAY 
        AS $$
        
          SELECT COALESCE(ARRAY_AGG(elem), '{}')
          FROM 
            UNNEST(array1) elem
          WHERE elem <> ALL (array2)
        
        $$ LANGUAGE SQL STRICT IMMUTABLE;
        

        并使用它(我在测试中添加了额外的记录 - 检查小提琴):

        SELECT
          ROW_NUMBER() OVER (ORDER BY NULL) rn,
          x, y,
          array_diff(y, x)
        FROM t
        ORDER BY rn;
        

        结果:

        rn        x                 y     array_diff
        1      {10}              {10}             {}
        2       {6}             {5,6}            {5}
        3   {4,5,6}             {5,6}             {}
        4     {5,6}             {5,6}             {}
        5     {7,8}              {11}           {11}
        6      {11}           {5,6,7}        {5,6,7}
        7      {11}               {8}            {8}
        8    {9,10}               {6}            {6}
        9      {11}   {5,8,10,11,133}   {5,8,10,133}
        10   {9,10} {4,5,6,8,9,10,11}   {4,5,6,8,11}
        11   {9,10} {4,5,6,8,9,10,11}   {4,5,6,8,11}
        

        查看(微不足道的)更新的小提琴。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-03-02
          • 1970-01-01
          • 1970-01-01
          • 2019-12-11
          • 2022-11-23
          • 1970-01-01
          • 2022-06-16
          • 1970-01-01
          相关资源
          最近更新 更多