我有这个问题:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
这很有效,但我还需要做一件事,我似乎无法弄明白。我需要从alerts.alert_type(警告表)==“声明”中的“学校”表IF数据中选择一些数据。
如果在alerts.alerts_table中找不到“claim”,那么它需要与上面的查询没有任何不同。 alerts.alert_table
这是我尝试过的,但它似乎不起作用:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,
IF(a.alert_type = 'claim', select s.* from schools where school_id = a.school_or_contact_id)
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
修改 为了澄清,我正在构建一个像Facebook一样具有首页“更新”类型的工具。根据用户的行为,“警报”会说不同的内容。
学校表有3,000行,仅当警告行alert_type.alerts ==“claim”时才会应用于警报表。否则,学校表中的内容无关紧要。如果alert_type.alerts!=“claim”,则“contacts”表将是其余数据的来源。
我想在进行查询时获得更清晰的数据(即 - 当warning_type.alerts!=“claim”时,不是“school”表数据)但我可以在PHP中轻松完成此操作。我只是不想提取我不会使用的数据。
感谢大家的所有帮助和建议!
第二次修改 我将更改表架构。现在,它看起来像这样:
mysql> desc alerts;
+----------------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(12) | YES | | NULL | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
| msg_title | varchar(100) | YES | | NULL | |
| message | longtext | YES | | NULL | |
| alert_type | varchar(255) | YES | | NULL | |
| school_or_contact_id | int(12) | YES | | NULL | |
+----------------------+--------------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)
我将警报表编辑到此(下方),然后加入alerts.school_id = schools.school_id。这应该可以解决问题。
+----------------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(12) | YES | | NULL | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
| msg_title | varchar(100) | YES | | NULL | |
| message | longtext | YES | | NULL | |
| alert_type | varchar(255) | YES | | NULL | |
| school_id | int(12) | YES | | NULL | |
| contact_id | int(12) | YES | | NULL | |
+----------------------+--------------+------+-----+-------------------+----------------+
答案 0 :(得分:3)
你不能像在上面的SQL中那样尝试可选的JOIN。
每列需要一个IF子句,即IF (a.alert_type = 'claim', s.col, NULL)
由于您已经加入了学校表,因此性能不会有任何差异,在一个查询中获取数据将比运行多个查询更好。
一个例子:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,
IF (a.alert_type = 'claim', s.col1, NULL) AS col1,
IF (a.alert_type = 'claim', s.col2, NULL) AS col2
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
如果碰巧你在学校表中有很多字段,你也可以只获取s。*,避免使用IF部分,只需在PHP脚本中跳过这些值。
答案 1 :(得分:2)
可能最好的方法是使用PHP检查alert_type并在需要时运行第二个查询。然后,您可以将两个结果合并在一起。
你可以试试这个:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name, s.*
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id AND a.alert_type = 'claim'
ORDER BY a.date
答案 2 :(得分:0)
您无法将查询嵌入到IF()调用中。有什么理由你不能无条件地进行子查询然后过滤客户端应用程序中的值?无论如何,当子查询替换字段时,不能让子查询返回多个字段。因此,即使IF()调用是可能的,子查询也必须返回单个字段/行。
答案 3 :(得分:0)
让我向您介绍UNION SELECT。
请注意,这将是一个长期的查询,并取决于学校的确切结构;以下假定有两个字体xs.foo
和xs.bar
:
SELECT * FROM
(SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,
a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,NULL,NULL
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
WHERE xa.alert_type!='claim'
UNION SELECT xa.id as alert_id,xa.user_id,xa.date,xa.msg_title,xa.message,
xa.alert_type,xa.school_or_contact_id,
xu.id as user_id, xu.full_name,
xc.id as contact_id, concat(xc.f_name,' ',xc.l_name) as contact_name,xs.foo,xs.bar
FROM alerts xa
LEFT OUTER JOIN users xu ON xa.user_id = xu.id
LEFT OUTER JOIN contacts xc ON xa.school_or_contact_id = xc.id
LEFT OUTER JOIN schools xs ON xa.school_or_contact_id = xs.school_id
WHERE xa.alert_type='claim')
ORDER BY date
警告:这很复杂,这是一个很好的迹象,表明您的数据库设计不当。如果你继承了这个...问题,那么就这样吧,但是如果你正在创建以这种方式工作的新代码,那么我强烈建议你对数据进行建模,这样一个完整的外部联接做正确的事情。
答案 4 :(得分:0)
正如其他人所解释的那样,结果集中不可能有可变数量的列。
你最接近你想要的可能是:
SELECT a.id as alert_id
, a.user_id
, a.date
, a.msg_title
, a.message
, a.alert_type
, a.school_or_contact_id
, u.id as user_id
, u.full_name
, c.id as contact_id
, concat(c.f_name,' ',c.l_name) as contact_name
, s.*
FROM alerts a
FROM alerts a
LEFT OUTER JOIN users u
ON a.user_id = u.id
LEFT OUTER JOIN contacts c
ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s
ON a.school_or_contact_id = s.school_id
AND a.alert_type = 'claim'
ORDER BY a.date