Mysql中水平合并两个没有公共列的表

问题描述 投票:0回答:1

我正在练习使用 MySQL 中的

sakila
数据库。有一个表名称
actor
和一列
last_name
。我想列出所有在第一列中不重复且在第二列中重复的last_name。

输入(只是简单的数据,实际数据存在于sakila数据库Mysql上):

insert into sakila.actor (actor_id, first_name, last_name, last_update)
values  (1, 'PENELOPE', 'GUINESS', '2006-02-15 04:34:33'),
        (2, 'NICK', 'WAHLBERG', '2006-02-15 04:34:33'),
        (3, 'ED', 'CHASE', '2006-02-15 04:34:33'),
        (4, 'JENNIFER', 'DAVIS', '2006-02-15 04:34:33'),
        (5, 'JOHNNY', 'LOLLOBRIGIDA', '2006-02-15 04:34:33'),
        (6, 'BETTE', 'NICHOLSON', '2006-02-15 04:34:33'),
        (7, 'GRACE', 'MOSTEL', '2006-02-15 04:34:33'),
        (8, 'MATTHEW', 'JOHANSSON', '2006-02-15 04:34:33'),
        (9, 'JOE', 'SWANK', '2006-02-15 04:34:33'),
        (10, 'CHRISTIAN', 'GABLE', '2006-02-15 04:34:33');

预期输出: 结果中,如果某一列的微粒行数多于其余列,则其余列中的数据将为空

不重复 重复
阿斯泰尔 阿克罗伊德
BACALL 艾伦
贝尔 贝利
贝宁
巴里摩尔 浆果
贝辛格 博尔格
卑尔根 布罗迪
伯格曼 笼子
桦木
绽放

我有一个具有

row_number()
功能的解决方案。还有其他解决方案可以解决这个问题吗?希望可以有人帮帮我。预先感谢您!

WITH group_last_name AS
         (SELECT last_name,
                 CASE
                     WHEN count(*) > 1 THEN 'many'
                     ELSE 'once'
                     END AS frequency
          FROM actor
          GROUP BY last_name),
     onceTbl AS
         (SELECT last_name,
                 row_number() OVER (PARTITION BY frequency) AS idx
          FROM group_last_name
          WHERE frequency = 'once'),
     manyTbl AS
         (SELECT last_name,
                 row_number() OVER (PARTITION BY frequency) AS idx
          FROM group_last_name
          WHERE frequency = 'many')
SELECT onceTbl.last_name AS not_repeated,
       manyTbl.last_name AS repeated
FROM manyTbl
         LEFT OUTER JOIN onceTbl ON onceTbl.idx = manyTbl.idx
UNION
SELECT onceTbl.last_name AS not_repeated,
       manyTbl.last_name AS repeated
FROM onceTbl
         LEFT OUTER JOIN manyTbl ON onceTbl.idx = manyTbl.idx;
mysql row-number
1个回答
0
投票

您可以同时分配列号和行号,为了应对空值,选择不同的行号,最后连接不同的行号并使用条件聚合输出来分隔列

with cte as
(
select last_name, count(*) ,
        case when count(*) >1 then 2 else 1 end columnno,
        row_number() over (order by last_name) rn
from actor a
group by last_name having count(*) = 1
union all
select last_name, count(*) ,
        case when count(*) >1 then 2 else 1 end columnno,
        row_number() over (order by last_name) rn
from actor a
group by last_name having count(*) > 1
)
,cte1 as
(select distinct rn from cte)
select max(case when columnno = 1 then last_name else null end) onlyone,
       max(case when columnno = 2 then last_name else null end) morethanone
from cte1 
join cte on cte.rn = cte1.rn
group by cte1.rn
order by cte1.rn
;

https://dbfiddle.uk/Y9Tq1OhT

© www.soinside.com 2019 - 2024. All rights reserved.