簡體   English   中英

比較同一表中的 3 列的一組行

[英]Compare 3 columns in same table for a group of rows

我必須根據 id 為每個組比較同一表的 3 列中的值。 最好說明我想要實現的目標:

create table test1 (id nvarchar(8), Name1 nvarchar(10), current_sem nvarchar(10), next_sem nvarchar(10), prev_sem nvarchar(10))

INSERT INTO test1 VALUES ('R001', 'Michael', 'Physics', 'Maths', 'Physics')
INSERT INTO test1 VALUES ('R001', 'Michael', 'Physics', 'Maths', 'Chemistry')
INSERT INTO test1 VALUES ('R003', 'Tim', 'Physics', 'Maths', 'Maths')
INSERT INTO test1 VALUES ('R002', 'John', 'Physics', 'Maths', 'Commerce')
INSERT INTO test1 VALUES ('R003', 'Tim', 'Maths', 'Maths', 'Physics')
INSERT INTO test1 VALUES ('R002', 'John', 'Maths', 'Commerce', 'Physics')
INSERT INTO test1 VALUES ('R002', 'John', 'Commerce', 'Physics', 'Maths')
INSERT INTO test1 VALUES ('R003', 'Tim', 'History', 'Civics', 'HomeEc')
INSERT INTO test1 VALUES ('R003', 'Tim', 'Drama', 'Chemistry', 'HomeEc')

表中的最后 3 列是: current_semnext_semprev_sem

對於每個 id,我想找到在 current_sem 或 prev_sum 中存在或不存在的 next_sem 的值,並顯示在名為“Sub_to_add”的偽列下。

對於相同的 id,還有另一個名為“Sub_to_remove”的偽列,其中包含在 next_sem 或 prev_sem 中不存在的 current_sem 的值。 因此,如果我們看到上述數據 id R001 (Michael) 將 Maths 作為 sub_to_add,因為 Maths 不存在於 R001 的 current_sem 或 prev_sem 中。

理想情況下不應顯示 R002,因為所有 next_sem 值都存在於 current_sem 或 prev_sem 中。 同樣沒有 sub_to_remove。

R003 將在 sub_to_add 下有 Civics;Chemistry,在 sub_to_remove 下有 History:Drama。

我不確定如何在代碼中顯示輸出,所以我添加了一個屏幕截圖。

在此處輸入圖像描述

我不能在WHERE子句中使用( next_sem <> current_sem OR next_sem <> prev_sem) ,因為同一列的另一行中可能存在一個值 - R002 的示例。

id      |   Name1   |   Sub_to_add          | Sub_to_remove
--------------------------------------------------------------
R001    |   Michael |   Maths               |
R003    |   Tim     |   Civics:Chemistry    | History;Drama

所以,我在這里尋求幫助。 此查詢將用於 SQL Server 2019 v15。

感謝您提醒我現在使用 PostgreSQL 而不是 SQL Server 是多么感激。 這非常痛苦,主要是因為您的數據模型,但也因為 SQL Server 的限制。

我對您的數據進行了標准化,這簡化了計算必要更改的過程。

with norm as (
  select id, Name1, 'current' as sem, current_sem as subj from test1
  union
  select id, Name1, 'next' as sem, next_sem as subj from test1
  union
  select id, Name1, 'prev' as sem, prev_sem as subj from test1
), rules as (
  select id, Name1, 'add' as change, subj
    from norm t
   where sem = 'next'
     and not exists (
           select 1
             from norm
            where id = t.id 
              and sem != t.sem
              and subj = t.subj
       )
  union all
  select id, Name1, 'remove' as change, subj
    from norm t
   where sem = 'current'
     and not exists (
           select 1
             from norm
            where id = t.id
              and sem != t.sem
              and subj = t.subj
       )
)
select t.id, t.Name1, 
       string_agg(
         case
           when r.change = 'add' then subj
           else null
         end,
         ';'
       ) as sub_to_add,
       string_agg(
         case 
           when r.change = 'remove' then subj
           else null
         end,
         ';'
       ) as sub_to_remove
  from (select distinct id, Name1 from test1) t
       left join rules r 
         on r.id = t.id
 group by t.id, t.Name1
 order by t.id
 ;
  

db<> 在這里擺弄

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM