MySQL Join 只从一系列条件中选择了一个条件
MySQL Join chose only 1 condition from a series of conditions
我有一个客户 table 和一个单独的 table 存储客户地址。他们通常在地址 table 中至少有两个连接记录,如果不是更多的话。当我想要一个邮寄列表时,我想要客户的账单地址,在地址 table 中用 'type' 列标记。不幸的是,并非每个客户都有一个标记为 'billing' 的地址。我怎样才能写一份声明,说要选择标记为账单的地址,除非没有,在这种情况下选择另一个。我不想只使用 'or' 因为我只想选择一条记录。
为简单起见,tables 可能如下所示:
Customer:
id
Address:
id
custid
type (shipping, billing, '', etc)
还有一些 sql 不是我想要的(笑):
Select * 来自 address.custid = Customer.id 上的客户内部加入地址,其中 Address.type = 'billing'
!!后期添加!!
Kevin 提供了我非常喜欢的合并解决方案,但它只适用于地址 table 中的单个列。我需要 table 中的所有 fields/columns 来形成可用地址。
我一直在尝试这样做(为了简单起见,这里只使用了两个字段):
select coalesce(concat_ws(',',a1.address, a1.city), concat_ws(',',a2.address, a2.city), concat_ws(',',a3.address, a3.city)) from customer c ...
但是,concat_ws 总是返回非空值,从而破坏了合并。
我还尝试在每个字段上独立进行合并:
coalesce(a1.address, a2.address), coalesce(a1.address2, a2.address2), etc
但这具有来自 3 个不同记录的 'mixing up' 地址的效果,如果例如 address2(用于公寓号或其他)对于一行为 null,则它将在其中插入不同记录的 address2。
有谁知道如何防止 concat_ws 返回非空值,即使字段内部为空值也是如此?
select c.id, a.id
from customer c join address a on a.custid = c.id
where a.type = 'Billing'
union
select c.id, a.id
from customer c join address a on a.custid = c.id
where a.type <> 'Billing'
and c.id not in (select custid from address a where a.type = 'Billing')
这是一种方法。
如果没有 OR 子句,很难做到这一点。假设您要查找地址 ID:
SELECT
Address.id
FROM Address LEFT JOIN Customer ON Customer.id = Address.custid
WHERE Address.id EXIST (
SELECT
Address.id
FROM Address LEFT JOIN Customer ON Customer.id = Address.custid
WHERE Address.type LIKE 'shipping'
) OR Address.type = 'billing'
这将为您提供帐单地址(如果存在),否则送货地址:
select ifnull(a1.address, a2.address) from customer c
left join address a1 on c.id = a1.custid and a1.type = 'billing'
left join address a2 on c.id = a2.custid and a2.type = 'shipping'
如果您想检查其他类型,您可以添加连接并使用 coalesce 而不是 ifnull,如下所示:
select coalesce(a1.address, a2.address, a3.address) from customer c
left join address a1 on c.id = a1.custid and a1.type = 'billing'
left join address a2 on c.id = a2.custid and a2.type = 'shipping'
left join address a3 on c.id = a3.custid and a3.type = 'X'
select ...
from customer c join address a on a.custid = c.id
where a.type = 'Shipping'
union all
select ...
from customer c join address a on a.custid = c.id
where a.type = 'Billing' and not exists (
select 1 from address a2
where a2.custid = a.custid and a2.type = 'Shipping'
)
如果您需要它更通用一点,那么您可能会发现这个 "hack" 很有用:
select * from address
where id in (
select
min(case type
when 'Shipping' then 100000000
when 'Billing' then 200000000
when ... then 300000000
else 900000000
end + a.id) % 100000000 /* not sure of MySQL for modulo operation */
from address a
group by custid
)
我有一个客户 table 和一个单独的 table 存储客户地址。他们通常在地址 table 中至少有两个连接记录,如果不是更多的话。当我想要一个邮寄列表时,我想要客户的账单地址,在地址 table 中用 'type' 列标记。不幸的是,并非每个客户都有一个标记为 'billing' 的地址。我怎样才能写一份声明,说要选择标记为账单的地址,除非没有,在这种情况下选择另一个。我不想只使用 'or' 因为我只想选择一条记录。
为简单起见,tables 可能如下所示:
Customer:
idAddress:
id
custid
type (shipping, billing, '', etc)
还有一些 sql 不是我想要的(笑): Select * 来自 address.custid = Customer.id 上的客户内部加入地址,其中 Address.type = 'billing'
!!后期添加!!
Kevin 提供了我非常喜欢的合并解决方案,但它只适用于地址 table 中的单个列。我需要 table 中的所有 fields/columns 来形成可用地址。
我一直在尝试这样做(为了简单起见,这里只使用了两个字段):
select coalesce(concat_ws(',',a1.address, a1.city), concat_ws(',',a2.address, a2.city), concat_ws(',',a3.address, a3.city)) from customer c ...
但是,concat_ws 总是返回非空值,从而破坏了合并。
我还尝试在每个字段上独立进行合并:
coalesce(a1.address, a2.address), coalesce(a1.address2, a2.address2), etc
但这具有来自 3 个不同记录的 'mixing up' 地址的效果,如果例如 address2(用于公寓号或其他)对于一行为 null,则它将在其中插入不同记录的 address2。
有谁知道如何防止 concat_ws 返回非空值,即使字段内部为空值也是如此?
select c.id, a.id
from customer c join address a on a.custid = c.id
where a.type = 'Billing'
union
select c.id, a.id
from customer c join address a on a.custid = c.id
where a.type <> 'Billing'
and c.id not in (select custid from address a where a.type = 'Billing')
这是一种方法。
如果没有 OR 子句,很难做到这一点。假设您要查找地址 ID:
SELECT
Address.id
FROM Address LEFT JOIN Customer ON Customer.id = Address.custid
WHERE Address.id EXIST (
SELECT
Address.id
FROM Address LEFT JOIN Customer ON Customer.id = Address.custid
WHERE Address.type LIKE 'shipping'
) OR Address.type = 'billing'
这将为您提供帐单地址(如果存在),否则送货地址:
select ifnull(a1.address, a2.address) from customer c
left join address a1 on c.id = a1.custid and a1.type = 'billing'
left join address a2 on c.id = a2.custid and a2.type = 'shipping'
如果您想检查其他类型,您可以添加连接并使用 coalesce 而不是 ifnull,如下所示:
select coalesce(a1.address, a2.address, a3.address) from customer c
left join address a1 on c.id = a1.custid and a1.type = 'billing'
left join address a2 on c.id = a2.custid and a2.type = 'shipping'
left join address a3 on c.id = a3.custid and a3.type = 'X'
select ...
from customer c join address a on a.custid = c.id
where a.type = 'Shipping'
union all
select ...
from customer c join address a on a.custid = c.id
where a.type = 'Billing' and not exists (
select 1 from address a2
where a2.custid = a.custid and a2.type = 'Shipping'
)
如果您需要它更通用一点,那么您可能会发现这个 "hack" 很有用:
select * from address
where id in (
select
min(case type
when 'Shipping' then 100000000
when 'Billing' then 200000000
when ... then 300000000
else 900000000
end + a.id) % 100000000 /* not sure of MySQL for modulo operation */
from address a
group by custid
)