在一列上连接两个表,如果不可能在第二列上连接

Join two tables on one column and if not possible on second column

前言

我有两个table

CREATE TABLE `permissions` (
  `id` int(11) NOT NULL,
  `user` int(11) DEFAULT NULL,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci NULL,
  `orders_and_returns` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
  `transactions` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
  ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `status` int(11) NOT NULL,
  `access_level` int(11) NOT NULL,
  `name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
  ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

权限table有两种行,一种是配置文件

INSERT INTO permissions (`id`, `user`, `name`, `orders_and_returns`) VALUES (1, NULL, 'Admin', 1);

这意味着有一个名为 Admin 的配置文件,它授予查看订单的权限。 access_level = 1 的任何用户都是管理员,可以查看订单。

table还有第二种行

INSERT INTO permissions (`id`, `user`, `name`, `orders_and_returns`) VALUES (2, 2, NULL, 0);

这是用户特定的权限。用户 (id = 2) 可能有 access_level = 1,但此用户有一个覆盖,可撤销对订单的访问权限。这是必须用于确定其权限的行。

问题

我需要加载 table 中所有用户的权限。因此,当我加入用户权限 table 时,我基本上想看看我是否可以加入 users.id = permissions.user(意味着存在用户特定覆盖),如果不能,我想加入 users.access_level = permissions.id.我不确定该怎么做。

可能有如下两个查询,但排除了第一个查询中第二个查询的所有结果

1. SELECT email FROM users u JOIN permissions p ON u.id = p.user
2. SELECT email FROM users u JOIN permissions p ON u.access_level = p.id

2022-03-20 更新

hank will also have access_level = 1 meaning the profile is admin. But there is an override for it. The access_level value is not changed in the users table. With that change, your query returns 2 results for hank ; the profile and the override.

如果记录同时具有配置文件和 access_level,您需要首先对结果进行排名(首先通过覆盖)然后 return 仅第一个结果:

WITH cte AS(
  SELECT 
     email
     , IF(u.id = p.user
         , 'user specific override'
         , 'profile' 
     ) AS PermissionType
     , ROW_NUMBER() OVER(
        PARTITION BY u.id
        ORDER BY IF(u.id = p.user, 0, 1)
     ) AS RowNum
  FROM users u
        INNER JOIN permissions p ON u.id = p.user OR u.access_level = p.id
) 
SELECT *
FROM.  cte
WHERE RowNum = 1

结果:

email           | PermissionType         | RowNum
:-------------- | :--------------------- | -----:
john@examle.com | profile                |      1
hank@examle.com | user specific override |      1

db<>fiddle here


原答案

你试过简单的 OR

SELECT email, IF(u.id = p.user, 'user specific override', 'profile')
FROM  users u 
        INNER JOIN permissions p ON u.id = p.user OR u.access_level = p.id

结果:

email           | IF(u.id = p.user, 'user specific override', 'profile')
:-------------- | :-----------------------------------------------------
john@examle.com | profile                                               
hank@examle.com | user specific override                                

db<>fiddle here