Php 基于字段值的“条件”联接?

Php 基于字段值的“条件”联接?,php,mysql,sql,database-design,relational-database,Php,Mysql,Sql,Database Design,Relational Database,我正在工作的网站有3种不同类型的用户:管理员、申请人、审阅者。这些组中的每个组都有一些基本信息,这些信息需要存储在姓名、id、电子邮件等中,以及每个组独有的一些数据。我为每个特定组创建了一个用户表和一个表,以存储其唯一的数据 用户:id、f_名称、l_名称、电子邮件、用户类型 用户\管理员:id、用户\ id、办公室、emp \ U id 用户\申请人:id、用户\ id、dob、地址 用户\审阅者:id、用户\ id、活动\状态、地址、电话 如果用户类型为1申请者的用户登录,我将需要加入用户申

我正在工作的网站有3种不同类型的用户:管理员、申请人、审阅者。这些组中的每个组都有一些基本信息,这些信息需要存储在姓名、id、电子邮件等中,以及每个组独有的一些数据。我为每个特定组创建了一个用户表和一个表,以存储其唯一的数据

用户:id、f_名称、l_名称、电子邮件、用户类型 用户\管理员:id、用户\ id、办公室、emp \ U id 用户\申请人:id、用户\ id、dob、地址 用户\审阅者:id、用户\ id、活动\状态、地址、电话 如果用户类型为1申请者的用户登录,我将需要加入用户申请者表以检索其完整记录。我尝试使用一个联合,但我的表有很大不同的列

有没有一种方法可以根据用户的类型编写一个将连接到正确表的条件查询?我是不是走错了路


提前感谢你的帮助

要么通过编程实现,要么通过一系列case和LEFT连接实现

为了简单起见,让我们对一个表用户执行此操作,其中可以有一个类型为1普通用户、2高级用户或3管理员的用户。普通用户有一封电子邮件,但没有电话;超级用户有一个地址和一个名为superpower的字段;管理员有一个电话号码,其他什么都没有

由于您希望对所有对象使用相同的选择,因此您当然需要将所有这些对象放置在您的选择中:

然后您需要左连接来恢复这些

FROM user
LEFT JOIN users_data ON (user.id = users_data.user_id)
LEFT JOIN power_data ON (user.id = power_data.user_id)
LEFT JOIN admin_info ON (user.id = admin_info.user_id)
现在,未使用的字段将为空,但您可以提供默认值:

SELECT
    CASE WHEN user.type = 0 THEN email ELSE 'nobody@nowhere.com' END AS email,
    CASE WHEN user.type = 1 OR user.type = 2 THEN ... ELSE ... END as whatever,
    ...
您可以在联接本身中设置特定的WHERE条件,例如,如果您只需要J扇区的管理员,您可以使用

LEFT JOIN admin_info ON (user.id = admin_info.user_id AND admin_info.sector = 'J')
总的查询时间应该不会太长,因为大多数连接返回的信息很少,如果指定用户ID,它们实际上不会很快返回任何信息

您也可以使用UNION执行同样的操作,这会更快:

SELECT user.id, 'default' AS email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN user_data ON (user.id = user_data.user_id)
  WHERE ...
UNION
SELECT user.id, email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN power_data ON (user.id = power_data.user_id)
  WHERE ...
UNION
  ...
现在,如果指定用户ID,除一个查询外,所有查询都会很快失败。每个查询都有相同的WHERE repeated加上任何特定于表的条件。除非以编程方式生成联合版本,否则联合版本的可维护性较差,但应该稍微快一点


在所有情况下,我们都会建议您在适当的字段上保留更新的索引。

您可以通过编程方式执行,也可以通过一系列案例和左联接执行此操作

为了简单起见,让我们对一个表用户执行此操作,其中可以有一个类型为1普通用户、2高级用户或3管理员的用户。普通用户有一封电子邮件,但没有电话;超级用户有一个地址和一个名为superpower的字段;管理员有一个电话号码,其他什么都没有

由于您希望对所有对象使用相同的选择,因此您当然需要将所有这些对象放置在您的选择中:

然后您需要左连接来恢复这些

FROM user
LEFT JOIN users_data ON (user.id = users_data.user_id)
LEFT JOIN power_data ON (user.id = power_data.user_id)
LEFT JOIN admin_info ON (user.id = admin_info.user_id)
现在,未使用的字段将为空,但您可以提供默认值:

SELECT
    CASE WHEN user.type = 0 THEN email ELSE 'nobody@nowhere.com' END AS email,
    CASE WHEN user.type = 1 OR user.type = 2 THEN ... ELSE ... END as whatever,
    ...
您可以在联接本身中设置特定的WHERE条件,例如,如果您只需要J扇区的管理员,您可以使用

LEFT JOIN admin_info ON (user.id = admin_info.user_id AND admin_info.sector = 'J')
总的查询时间应该不会太长,因为大多数连接返回的信息很少,如果指定用户ID,它们实际上不会很快返回任何信息

您也可以使用UNION执行同样的操作,这会更快:

SELECT user.id, 'default' AS email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN user_data ON (user.id = user_data.user_id)
  WHERE ...
UNION
SELECT user.id, email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN power_data ON (user.id = power_data.user_id)
  WHERE ...
UNION
  ...
现在,如果指定用户ID,除一个查询外,所有查询都会很快失败。每个查询都有相同的WHERE repeated加上任何特定于表的条件。除非以编程方式生成联合版本,否则联合版本的可维护性较差,但应该稍微快一点


在所有情况下,都会建议您在适当的字段上保留更新的索引。

相反,我建议您像这样重构表结构

创建一个表

users_types : 
id 
type
然后使用外键创建另一个表users

users :     
id 
f_name 
l_name 
email 
office 
emp_id 
dob 
address 
active_status 
phone 
users_types_id

现在,当您需要在特定用户不需要的字段中插入数据insert null时。您可以简单地根据id获取记录。同样,使用left join将为您提供用户类型的名称。

相反,我建议您重构如下表结构

创建一个表

users_types : 
id 
type
然后使用外键创建另一个表users

users :     
id 
f_name 
l_name 
email 
office 
emp_id 
dob 
address 
active_status 
phone 
users_types_id

现在,当您需要在特定用户不需要的字段中插入数据insert null时。您可以简单地根据id获取记录。同时,使用left join将为您提供用户类型的名称。

好吧,最终您的表已经有缺陷了。为什么每种类型都有一张桌子?为什么不把所有这些字段都放在users表中,或者如果您真的想要为非常规数据字段添加一个额外的表,那么可以放在user\u details表中呢?目前,您实际上从关系的角度创建了4个独立的用户表

那么为什么类型表有一个代理键呢?为什么用户id不是唯一的主键

<
p> 如果你改变了这一点,你所需要的只是用户id来检索你想要的数据,而你已经得到了,或者你甚至无法检索用户类型。

好吧,最后你的表已经有缺陷了。为什么每种类型都有一张桌子?为什么不把所有这些字段都放在users表中,或者如果您真的想要为非常规数据字段添加一个额外的表,那么可以放在user\u details表中呢?目前,您实际上从关系的角度创建了4个独立的用户表

那么为什么类型表有一个代理键呢?为什么用户id不是唯一的主键



如果您改变了这一点,您所需要的只是用户id来检索所需的数据,而您已经获得了该id,否则您甚至无法检索用户类型。

为什么必须在SQL中而不是在PHP中进行此操作?你已经试过什么了?既然你一开始就要处理3组不同的列,为什么不处理3组不同的查询呢?@DanMan我想这也是我想知道的一件事。查询以获取用户的类型,然后使用PHP确定要使用的连接,这是一种不好的做法吗?@DanMan在下面是正确的,如果您在这里使用TPT,则转储表特定的键,并且基表中的Id键是您唯一需要的键。为什么必须在SQL中而不是在PHP中发生这种情况?你已经试过什么了?既然你一开始就要处理3组不同的列,为什么不处理3组不同的查询呢?@DanMan我想这也是我想知道的一件事。查询以获取用户的类型,然后使用PHP确定要使用的连接,这是一种不好的做法吗?@DanMan在下面是正确的,如果您在这里使用TPT,则转储表特定的键,并且基表中的Id键是您唯一需要的键。只有当用户可以有多个类型时,才会需要users\u types表。即使这样,您也可能会得到一个SET列。只有当用户可以有多个类型时,才会需要users\u types表。即使这样,您也可以使用一个SET列。使用一个users表不会有问题。考虑到每个用户类型需要不同的值,这将导致许多空字段,我认为这是需要避免的。不是这样吗?是的,但没有跨多个表运行复杂查询那么糟糕。只要这些空列不必为NULL,就可以-没什么大不了的。@Vecta Table per type是一个有效的数据库结构,不确定是否有足够的信息来确定它在这里是否被正确使用,但它在许多情况下非常有用。使用ORM时要容易得多,但不必担心这一部分。@Matthew:也许吧,但通过外键以外的任何东西关联条目绝对是一种糟糕的设计。因此,如果他想保持表的原样,他至少需要一个users\u types表,正如raheel shan所建议的那样。@DanMan同意-在我的回答中提出了类似的建议。使用一个users表不会有问题。考虑到每个用户类型需要不同的值,这将导致许多空字段,我认为这是需要避免的。不是这样吗?是的,但没有跨多个表运行复杂查询那么糟糕。只要这些空列不必为NULL,就可以-没什么大不了的。@Vecta Table per type是一个有效的数据库结构,不确定是否有足够的信息来确定它在这里是否被正确使用,但它在许多情况下非常有用。使用ORM时要容易得多,但不必担心这一部分。@Matthew:也许吧,但通过外键以外的任何东西关联条目绝对是一种糟糕的设计。所以,如果他想保持表的原样,他至少需要一个users\u types表,正如raheel shan所建议的那样。@DanMan同意-在我的回答中提出了类似的建议。