Mysql

加入沒有重複行/空值的表

  • March 26, 2018

所以我有多個表,我必須在查詢時合併,但兩者join似乎union都沒有實現我的對像是什麼

聯盟:

mysql>
SELECT  NAME, currentstatus, NULL AS username, NULL AS status
   FROM  statustable
   WHERE  Name like '%ahsan%'
UNION  ALL 
SELECT  NULL AS NAME, NULL AS currentstatus, username, status
   from  awsaccount
   WHERE  username like '%ahsan%';
+--------------+-------------------+----------+--------------------------------+
| NAME         | currentstatus     | status   | username                         |
+--------------+-------------------+----------+--------------------------------+
| Ahsan Naseem | activated         | NULL     | NULL                           |
| NULL         | NULL              | ACTIVE   | ahsan.naseem       |
| NULL         | NULL              | INACTIVE | ahsantest                      |
| NULL         | NULL              | ACTIVE   | ahsantest2                     |
| NULL         | NULL              | ACTIVE   | ahsantestuserprofileupdate     |
| NULL         | NULL              | INACTIVE | ahsantestuserprofileupdate_cli |
| NULL         | NULL              | INACTIVE | decent.ahsan         |
| NULL         | NULL              | INACTIVE | decent.ahsan_cli               |
+--------------+-------------------+----------+--------------------------------+
8 rows in set (0.00 sec)

加入:

mysql>
select  *
   from ( SELECT * from  statustable where     Name like '%ahsan%' ) as ab
   JOIN ( SELECT * from  awsaccount  where username like '%ahsan%' ) as asb;

   +--------------+-------------------+--------------------------------+----------+
   | Name         | currentstatus | username                       | status   |
   +--------------+-------------------+--------------------------------+----------+
   | Ahsan Naseem | activated         | ahsan.naseem                    | ACTIVE   |
   | Ahsan Naseem | activated         | ahsantest                      | INACTIVE |
   | Ahsan Naseem | activated         | ahsantest2                     | ACTIVE   |
   | Ahsan Naseem | activated         | ahsantestuserprofileupdate     | ACTIVE   |
   | Ahsan Naseem | activated         | ahsantestuserprofileupdate_cli | INACTIVE |
   | Ahsan Naseem | activated         | decent.ahsan         | INACTIVE |
   | Ahsan Naseem | activated         | decent.ahsan_cli               | INACTIVE |
   +--------------+-------------------+--------------------------------+----------+
   7 rows in set (0.00 sec)

我想要實現的是:

+--------------+-------------------+----------+--------------------------------+
| NAME         | currentstatus    | status   | username                       |
+--------------+-------------------+----------+--------------------------------+
| Ahsan Naseem | Active            | ACTIVE   | ahsan.naseem        |
| NULL         | NULL              | INACTIVE | ahsantest                      |
| NULL         | NULL              | ACTIVE   | ahsantest2                     |
| NULL         | NULL              | ACTIVE   | ahsantestuserprofileupdate     |
| NULL         | NULL              | INACTIVE | ahsantestuserprofileupdate_cli |
| NULL         | NULL              | INACTIVE | decent.ahsan        |
| NULL         | NULL              | INACTIVE | decent.ahsan_cli               |
+--------------+-------------------+----------+--------------------------------+

我是 sql 新手,將不勝感激您的意見和建議

首先,我應該注意這基本上是一個格式要求:如果前兩列中的值與前一列中的值相同,則您不想重複它們。如果您在應用程序端擁有比在 SQL Server 上更多的 CPU 能力,那麼如果您允許應用程序處理格式化要求,您將可能獲得更好的性能。

也就是說,有時 SQL Server 有足夠的容量來處理格式化,或者由於某種原因在應用程序端這樣做沒有意義。

以下查詢應該做你想做的事:

SET @PrevName := '';
SET @PrevStatus := '';
SET @RowNum := 0;

SELECT Name
     ,currentstatus
     ,`status`
     ,username
 FROM (
       SELECT IF(@PrevName = ab.Name, '', ab.Name) as Name
             ,IF(@PrevName = ab.Name AND @PrevStatus = ab.currentstatus, '', ab.currentstatus) as currentstatus
             ,asb.`status`
             ,asb.username
             ,@PrevName := ab.Name as ActualName
             ,@PrevStatus := ab.currentstatus as Act_curstatus
             ,@RowNum := @RowNum + 1 as RowOrder
         FROM statustable ab
                CROSS JOIN awsaccount asb
        WHERE (    ab.Name LIKE '%ahsan%'
               AND asb.username LIKE '%ahsan%'
              )
        ORDER BY ActualName, Act_curstatus
      ) sq
ORDER BY RowOrder
;

我通過 db-fiddle.com 對此進行了測試;您可以在此處使用查詢和測試數據。

快速解釋:

我們使用變數來保存前一行的Namecurrentstatus。如果Name不同,我們顯示兩個值;如果Name相同但currentstatus已更改,我們將Name留空但顯示新狀態。

如果我們有多個名稱或目前狀態,則建立訂單至關重要;如果我們不對這些進行排序,那麼具有不同名稱的行可能會被交錯,這意味著相同的名稱會重複多次,如下所示:

...
Ahsan Naseem        | activated   | ACTIVE   | ahsan.naseem 
                   |             | INACTIVE | ahsantest
Bruce Banner        | activated   | ACTIVE   | mr.green
Ahsan Naseem        | activated   | ACTIVE   | ahsantest2
                   |             | ACTIVE   | ahsantestuserprofileupdate
...

此外,我們必須保留處理行的順序,否則帶有名稱的行可能不是第一行,如下所示:

...
                   |             | INACTIVE | ahsantest
                   |             | ACTIVE   | ahsantest2
Ahsan Naseem        | activated   | ACTIVE   | ahsan.naseem 
                   |             | ACTIVE   | ahsantestuserprofileupdate
...

因此,我們使用@RowNum 在處理行時對行進行順序編號,並最終按該編號進行排序。(我不確定這是否需要;但是,如果沒有它,我的結果會倒過來,所以我顯然確實需要它!)

我們將查詢放在子查詢中,這樣我們就可以將處理後的順序強製到結果上,因此我們可以省略Actual_NameAct_currentstatusRowOrder列。

如果您真的想要NULL重複值而不是空字元串,只需將 IF 函式中的空字元串替換為 NULL。正如我假設這是出於顯示目的,空字元串可能是更好的選擇,但您可能有其他原因這樣做。

因此,如果我理解這一點,您希望從兩個表中獲取所有行,並在可能的地方加入它們。

您可以通過在它們之間使用 UNION 進行兩個連接來模擬 MySQL 中的完全外部連接。您只需在一側切換使用 LEFT 並在另一側切換使用 RIGHT。

SELECT * FROM statustable t1
LEFT JOIN awsaccount t2 ON t1.statustable_id = t2.awsaccount_id
UNION
SELECT * FROM statustable t1
RIGHT JOIN awsaccount t2 ON t1.statustable_id = t2.awsaccount_id;

我重用@RDFozz DB Fiddle 來模擬這個:DB Fiddle

引用自:https://dba.stackexchange.com/questions/183099