我有两个桌子,房屋和房客。每个单位有多个房客。 我需要的是一个联合列表,其中最多包含两个承租人,具有完整数据集的优先行,然后是电话号码和最后一个电子邮件地址。
我也想避免使用临时表和子查询,因为其中包含大量数据。 谢谢!
示例:
餐桌上的房子
-------------
| id | flat|
-------------
| 1 | 011 |
| 2 | 012 |
| 3 | 111 |
-------------
出租房
------------------------------
| fid | name | phone | mail |
------------------------------
| 1 | pete | NULL | NULL |
| 1 | cloe | NULL | cloe@..|
| 1 | bill | 555.. | bill@..|
| 2 | john | 555.. | john@..|
| 3 | paul | 555.. | NULL |
| 3 | mary | NULL | mary@..|
------------------------------
预期输出:
-----------------------------------------------------------------
| id | flat | name1 | phone1 | mail1 | name2 | phone2 | mail2 |
-------------
| 1 | 011 | bill | 555.. | bill@..| cloe | NULL | cloe@..|
| 2 | 012 | john | 555.. | john@..| NULL | NULL | NULL |
| 3 | 111 | paul | 555.. | NULL | mary | NULL | mary@..|
-----------------------------------------------------------------
答案 0 :(得分:0)
在MySQL8中:
SELECT
f.id,
f.flat,
MAX(CASE WHEN rr.rn = 1 THEN rr.`name` END) AS name1,
MAX(CASE WHEN rr.rn = 1 THEN rr.phone END) AS phone1,
MAX(CASE WHEN rr.rn = 1 THEN rr.mail END) AS email1,
MAX(CASE WHEN rr.rn = 2 THEN rr.`name` END) AS name2,
MAX(CASE WHEN rr.rn = 2 THEN rr.phone END) AS phone2,
MAX(CASE WHEN rr.rn = 2 THEN rr.mail END) AS email2
FROM
house f
LEFT JOIN
(
SELECT
r.*,
ROW_NUMBER() OVER(PARTITION BY r.fid ORDER BY
(CASE WHEN r.phone IS NOT NULL THEN -2 ELSE 0 END + CASE WHEN r.mail IS NOT NULL THEN -1 ELSE 0 END), r.fid
) rn
FROM
renter r
) rr
ON rr.fid = f.id and rr.rn <= 2
GROUP BY f.id, f.flat
在MySQL <8中,您必须使用以下未证明的(可能突然停止工作)技术来伪造ROW_NUMBER / PARTITION:
SELECT
f.id,
f.flat,
MAX(CASE WHEN rr.rn = 1 THEN rr.`name` END) AS name1,
MAX(CASE WHEN rr.rn = 1 THEN rr.phone END) AS phone1,
MAX(CASE WHEN rr.rn = 1 THEN rr.mail END) AS email1,
MAX(CASE WHEN rr.rn = 2 THEN rr.`name` END) AS name2,
MAX(CASE WHEN rr.rn = 2 THEN rr.phone END) AS phone2,
MAX(CASE WHEN rr.rn = 2 THEN rr.mail END) AS email2
FROM
house f
LEFT JOIN
(
SELECT
r.*,
@rn:=CASE WHEN r.fid=@previd THEN @rn+1 ELSE 1 END as rn,
@previd:=r.fid
FROM
(select @rn:=0,@previd:=-1) x,
renter r
ORDER BY r.fid, (CASE WHEN r.phone IS NOT NULL THEN -2 ELSE 0 END + CASE WHEN r.mail IS NOT NULL THEN -1 ELSE 0 END)
) rr
ON rr.fid = f.id and rr.rn <= 2
GROUP BY f.id, f.flat
https://www.db-fiddle.com/f/dYS68AFFGTxZxfia1UtJEK/0
您的承租人表已应用行号,该行号按优先级对行进行计数。如果一行中有电话,则得分为-2,如果一行中有电子邮件,则得分为-1。如果一行同时包含两者,则总和为-3。当升序排列时,这意味着-3的优先级(是排序的第一行)比-2或-1高。行号在行上放置一个数字,例如1,2,3 ..每次平面编号更改时都会重新启动。
我们将扩充后的数据集连接到平面上,并且说我们只对行号<= 2的行感兴趣,因为您只需要name1和name2等。
但是此数据仍在单个列中:
FlatID, Name, RN
1, Bill, 1
1, Cloe, 2
要将该列变成一行,我们使用枢轴操作。执行此操作的标准方法是使用CASE WHEN rn = 1 or 2 ...
:
SELECT *, case when rn = 1 then name end as name, case when rn = 2 then name end
生产
FlatID, Name1, Name2, RN
1, Bill, null, 1
1, null, Cloe, 2
现在,我们使用MAX()将FlatID分组为一行,并且由于MAX丢弃了空值,因此Bill和Cloe被保留并变成一行。 RN已经完成工作并被丢弃:
FlatID, Name1, Name2
1, Bill, Cloe
底部查询(mysql5.x)使用相同的技术,它仅使用变量来模仿row_number()
对于以后的问题,请确保您发布MySQL版本,并尝试在db-fiddle.com上制作一组示例数据(如我上面所做的)或类似内容-如果他们不必费心创建表并向其加载数据以测试其理论