2014-11-03 44 views
0

我有以下查询:MySQL的 - 有条件加入了列

select ad_st_id_state, count(distinct id_visit) as Visits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 

group by ad_st_id_state 
order by ad_st_id_state 

,我也有这样的一个:

正如你所看到的查询是几乎除了同一个额外的join声明。 两个查询返回我,我需要正确的价值观,但我需要他们一起在一个单一的表,所以我这样做:

select fffuuu.ad_st_id_state, count(distinct id_visit) as Visitas, fffuuu.doneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 

join (
select ad_st_id_state, count(distinct id_visit) as doneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
join sf_visit_file_time on id_visit = vft_vi_id_visit 

group by ad_st_id_state 
order by ad_st_id_state 
) as fffuuu on sf_address.ad_st_id_state = fffuuu.ad_st_id_state 

group by ad_st_id_state 
order by ad_st_id_state 

或者换句话说,我加入了第一个查询与第二个作为子查询。结果集很好而且正确,但花费的时间太长,所以我在这个查询正在运行的另一个系统中出现超时。 每个查询独立运行速度快,但加入他们是太慢我的需求...

我想知道是否有一种方法来优化这个,我想如果有一些联合条件语句或某事。我搜索了信息,但我没有任何运气。 我在想像这样的东西:

select ad_st_id_state, count(distinct id_visit) as Visits, if(@someVariable := true) as DoneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
if (@someVariable == true) then join sf_visit_file_time on id_visit = vft_vi_id_visit 

group by ad_st_id_state 
order by ad_st_id_state 

或类似的东西。请问一些身体可以帮我吗?我怎样才能优化这个? 感谢

+0

在T-SQL下工作,是使我确定这将在MySQL工作太添加加入像....上id_visis = vft_vi_id_visit和@someVariable = 1个 – SkelDave 2014-11-03 19:59:21

+0

@SkelDave JOIN sf_visit_file_time我想你的建议,但我不知道该怎么做,因为我在MySQL中遇到了语法错误。我只是编写了关于someVariable的代码来阐明我想要做的事情。 – Metafaniel 2014-11-03 20:07:14

回答

4

你可以使用一个外部连接来计算sf_visit_file_time和一个case语句吗?很明显,我没有本地模式,但类似于:

select ad_st_id_state, 
    count(distinct id_visit) as Visits, 
    count(distinct case when vft_vi_id_visit is not null then id_visit end) as DoneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
left join sf_visit_file_time on id_visit = vft_vi_id_visit 
group by ad_st_id_state 
order by ad_st_id_state 
+0

戈登就够了。在我的示例中,第一个计数获取的访问次数未完成,而不是所有访问次数。在第二个中,我添加了0,因为我担心在mysql中为null添加null,我没有一个实例方便地检查它的作用。我从你的回答中假设,它增加了一个0? – 2014-11-03 20:11:09

+0

戈登,根据您的反馈回答编辑。 – 2014-11-03 20:13:44

+0

嘿,你们都做到了!这个答案也适用,它更短,更清晰!在选择最好的答案之前,我想给每个答案都给予适当的阅读,但我非常喜欢这个答案。非常感谢你的努力! – Metafaniel 2014-11-03 20:52:38

1

如果这两个查询是速度快,很好地工作,你只需要在一个表中的结果,你可以使用一个联盟选择http://dev.mysql.com/doc/refman/5.0/en/union.html

select ad_st_id_state, count(distinct id_visit) as Visits, '' as DoneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
group by ad_st_id_state 
UNION 
select ad_st_id_state, '' as Visits, count(distinct id_visit) as DoneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
join sf_visit_file_time on id_visit = vft_vi_id_visit /* Another join has been added */ 
group by ad_st_id_state 
order by ad_st_id_state 
+0

我试过了,但是我得到了一个错误代码:1221.UNION和ORDER BY的用法不正确可能我对'union' = P不太了解我很少使用它。你能请进一步解释我吗?我只是在括号中加入每个查询并添加'union' = P – Metafaniel 2014-11-03 19:57:25

+0

@Metafaniel为您添加了一个样本。我假设你想区分访问和完成访问者。 – SLin 2014-11-03 20:05:54

+0

感谢这似乎是有用的,我理解'union'更好的这个例子,但是,而不是数字,我在我的结果集中有'BLOB'标志。任何想法为什么?再次感谢 – Metafaniel 2014-11-03 20:10:37

0

在这种情况下,你是“有条件加入”被告诉你“如果我在另一张表中找到记录,这意味着访问完成。”

为了创造“条件”您可以使用LEFT OUTER JOIN,而不是一个INNER JOIN

OUTER JOIN,而不是一个INNER JOIN如果记录在表中找到,而不是其他不破。它仍然会返回记录。有LEFTRIGHT外连接。你应该自己研究它们。但基本上,以达到你想要什么,你可以做这样的事情:

select ad_st_id_state, count(distinct vft_vi_id_visit) as DoneVisits 
from sf_visit 
join vr_users on vi_us_id_user = sus_us_id_user 
join sf_pdv on vi_pdv_id_pdv = id_pdv 
join sf_address on pdv_ad_id_address = id_address 
left outer join sf_visit_file_time on id_visit = vft_vi_id_visit /* Another join has been added */ 
group by ad_st_id_state 
order by ad_st_id_state 

所以,现在,DoneVisits将永远存在 - 它只是为零时,有没有sf_visit_file_time记录它。

+0

我理解你的观点,但在这种情况下,'left outer join'会返回Visits值,'inner join'会返回DoneVisits值,但我需要在一个结果集中使用这两个值。感谢您的回答 – Metafaniel 2014-11-04 15:39:40

+0

这就是要做的。我现在看到'id_visit'是计算DISTINCT的错误列。它应该是'vft_vi_id_visit'。我相应地更新了我的答案。尽管如此,所描述的概念正是您所需要的,正如您接受的答案所表明的那样。 – 2014-11-04 17:41:40

1

这两个查询都干净而高效。所以,只需将它们连接在一起进行演示,将它们当作子查询处理。

SELECT a.ad_st_id_state, a.Visits, b.DoneVisits 
    FROM (
     /* put your first query here */ 
     ) AS a 
    LEFT JOIN (
     /* put your second query here */ 
     ) AS b ON a.ad_st_id_state = b.ad_st_id_state 
ORDER BY a.ad_st_id_state 

这使得一个更大的查询,但它应该在你有两个查询的时间之和运行。您可以将ORDER BY子句保留在子查询中。

因此,它看起来像这样......一个真正的查询俱乐部三明治。

SELECT a.ad_st_id_state, a.Visits, b.DoneVisits 
    FROM (
      select ad_st_id_state, count(distinct id_visit) as Visits 
      from sf_visit 
      join vr_users on vi_us_id_user = sus_us_id_user 
      join sf_pdv on vi_pdv_id_pdv = id_pdv 
      join sf_address on pdv_ad_id_address = id_address 
      group by ad_st_id_state 
     ) AS a 
    LEFT JOIN (
      select ad_st_id_state, count(distinct id_visit) as DoneVisits 
      from sf_visit 
      join vr_users on vi_us_id_user = sus_us_id_user 
      join sf_pdv on vi_pdv_id_pdv = id_pdv 
      join sf_address on pdv_ad_id_address = id_address 
      join sf_visit_file_time on id_visit = vft_vi_id_visit /* Another join */ 
      group by ad_st_id_state 
     ) AS b ON a.ad_st_id_state = b.ad_st_id_state 
ORDER BY a.ad_st_id_state 
+0

我已经设法遵循你的答案,我已经得到了期望的结果!而且比我想要做的要快得多。你说得对,我只需要一个三明治就可以了。我试图找出其他答案,但可能这个答案就是答案。谢谢 – Metafaniel 2014-11-03 20:22:45