2013-07-10 51 views
1

我不确定这是否可行,并且描述确实很难。MySQL - 选择内的子查询

我想以这种方式返回SELECT查询:

 
pID | Name | Email   | Dog Name | Fish Name 
------------------------------------------------------- 
44 | John | [email protected] | Scruffy | 
56 | Jane | [email protected] |   | Puffer 
72 | Joe | [email protected] | Sparky | Gill 

有3个表: tbl_option_fields tbl_person tbl_person_optionals

第一个表只定义无限的可选字段。下面是列:

 
optid | opttitle 
------------------ 
1  | Dog Name 
2  | Fish Name 
3  | Email 

第二个表只是,我保证数据的人:

 
pID | Name 
--------------- 
44 | John 
56 | Jane 
72 | Joe 

最后一个表让我存储的存在是有pID

 
ID | pID | optid | optval 
---------------------------------- 
1 | 44 | 1 | Scruffy 
2 | 56 | 2 | Puffer 
3 | 72 | 1 | Sparky 
4 | 72 | 2 | Gill 
5 | 72 | 3 | [email protected] 
6 | 56 | 3 | [email protected] 
7 | 44 | 3 | [email protected] 
任何可选数据

SELECT语句的结果需要在结果的标题中显示opttitle。 我不擅长子查询,这可能是一个愚蠢的。

这里是我的尝试:

SELECT p.*, opt.optval 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
WHERE 1 

此查询导致重复的结果,我相信我明白为什么。

 
pID | Name | optval    
----------------------------- 
44 | John | [email protected] 
44 | John | Scruffy 

56 | Jane | [email protected] 
56 | Jane | Puffer 

72 | Joe | [email protected] 
72 | Joe | Sparky 
72 | Joe | Gill 

希望我解释说我想水平显示可选字段,而不是行中的新记录。 可以这样做吗?

+1

你在找什么是一个数据透视查询,但mysql不直接支持它们。有解决方法,但它们会导致丑陋的语法,并且当您在旋转结果中添加/需要更多列时,它们不会自动放大。 –

+0

这可能是我需要听到的。谢谢! – coffeemonitor

回答

0

你基本上想要的是一个数据透视表。这可以在MySQL中完成,如this article describes in full, glorious detail

然而,为了archieve你将不得不在你的表tbl_option_fields添加SELECT - 运算符为你拥有的每选择要与当前的表设计的东西。只有少数几个选项是可以管理的,但是您拥有的选项越多,您的声明就会变得越混乱(并且最终执行速度会越慢)。

另一个缺点是每当有新选项出现时,您的陈述就必须进行调整。

基本上或者你必须忍受它或调整你的餐桌设计。可能还有更多的选择,但我想可以归结为那两个。

0

这里有一个解决方案:

SELECT p.pID, p.Name, 
    MAX(IF(opt.optid=3, opt.optval, NULL)) AS `Email`, 
    MAX(IF(opt.optid=1, opt.optval, NULL)) AS `Dog Name`, 
    MAX(IF(opt.optid=2, opt.optval, NULL)) AS `Fish Name` 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
GROUP BY p.pID; 

你必须知道所有的optid的和他们的标签栏写这个查询之前。这对于MySQL来说是正确的,但支持本地PIVOT命令(例如Microsoft SQL Server)的RDBMS品牌也是如此。 SQL要求您在开始检查数据之前定义查询的列;该查询不能“添加”更多的列,因为它发现不同的数据值。

所以你应该查询你的第一个表,它定义了可选字段,并使用结果动态地写上面的SQL查询。

另一种方法是按照您在示例中所示的方式逐行获取可选字段,然后编写应用程序代码以获取所有行并将其重新排列为每人一行。

无论哪种方式:任何动态数据透视查询都要求您在查询之前或查询之后编写更多的应用程序代码。

0

您可以通过加入表一起,并综合这些结果做到这一点:

select po.pid, p.name, 
     MAX(case when o.optId = 'Email' then po.optval end) as Email, 
     MAX(case when o.optId = 'Dog Name' then po.optval end) as DogName, 
     MAX(case when o.optId = 'Fish Name' then po.optval end) as FishName 
from tbl_person_optionals po join 
    tbl_person p 
    on p.pId = p.pId join 
    tbl_optionfields o 
    on p.optid = o.optid 
group by po.pid, p.name; 

这是假设你知道你在列想要的东西。 Select语句只能返回一组固定的列,所以如果您想为tbl_optionfields中的每个值返回一个单独的列,则需要动态SQL(即使用prepare语句)。