SQL外连接?

时间:2014-08-27 19:55:34

标签: sql tsql

我有这样的表格:

Fields (ID int, Name varchar(20))

ID     Name
===============
1      FieldName
2      FeildDesc

Container (ID int, Name varchar(100))

ID     Name
====================================
1      C1       
2      C2
3      C3

ContainerField (ContainerId int, FieldId int, FieldValue varchar(100))

ContainerId    FieldId    FieldValue
====================================
1              1          Container1
1              2          Container1 Desc
2              1          Container2
2              2          Container3 Desc
3              1          Container3

我希望我的结果如下:

ContainerId    Name          Desc
===================================
1              Container1    Container1 Desc
2              Container2    Container2 Desc
3              Container3    NULL

我尝试在ContainerField和Field之间进行LEFT OUTER JOIN,但这似乎不起作用。如果有人能提供帮助,我会很感激。

5 个答案:

答案 0 :(得分:3)

加入表格两次,一次是名字,一次是说明。

select
  c.Id as ContainerId,
  cfn.FieldValue as Name,
  cfd.FieldValue as Desc
from
  Container c
  left join ContainerField cfn
    on cfn.ContainerId = c.ID and cfn.FieldId = 1
  left join ContainerField cfd
    on cfd.ContainerId = c.ID and cfd.FieldId = 2

如您所见,不是群组或聚合。此外,您在查询中并不真正需要Fields tabel本身,尽管将它放在数据库中是很好的,因为它强制引用完整性(如果您有正确的密钥)并且它提供了一种文档。但你也可以使用枚举。

或者,如果您不仅有两个字段,但其数目未知,则可能需要考虑pivot tables。我必须承认我对这些并不是很好,特别是在TSQL中,所以我会为你提供一个链接供你探索:http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx或者希望其他人可以给你一个具体的例子。

答案 1 :(得分:1)

不需要外部联接,内部联接将执行此操作。您还没有使用Container中的任何内容(如果您想显示容器名称而不是ID,则可以使用它进行内部联接以获取该内容)。

SELECT c.id AS ContainerID,
       MAX(CASE WHEN f.name = 'FieldName' THEN c.FieldValue END) AS Name,
       MAX(CASE WHEN f.name = 'FieldDesc' THEN c.FieldValue END) AS `Desc`
FROM ContainerField AS c
JOIN Fields AS f ON c.FieldID = f.id
GROUP BY ContainerID

DEMO

请注意,您的Fields表格中存在拼写错误:FeildsDesc应为FieldsDesc

答案 2 :(得分:1)

不妨投入我的两分钱。这将为您提供所需的一切。它在Oracle中完成但应该也一样。

编辑:SQL Fiddle Demo了解一个工作示例。

Select * From (

WITH 
/* Example Tables.*/
Container As
(
    Select 1 as ID, 'C1' as Name From Dual Union All       
    Select 2 as ID, 'C2' as Name From Dual Union All
    Select 3 as ID, 'C3' as Name From Dual
)

,ContainerField as
(
    Select 1 as ContainerId, 1 as FieldId, 'Container1     ' as FieldValue From Dual UNION ALL
    Select 1 as ContainerId, 2 as FieldId, 'Container1 Desc' as FieldValue From Dual UNION ALL
    Select 2 as ContainerId, 1 as FieldId, 'Container2     ' as FieldValue From Dual UNION ALL
    Select 2 as ContainerId, 2 as FieldId, 'Container2 Desc' as FieldValue From Dual UNION ALL
    Select 3 as ContainerId, 1 as FieldId, 'Container3     ' as FieldValue From Dual
)

/*Code*/
Select
    C.ID, 
    Max(Case When CF.FieldId = 1 Then FieldValue End) as Name,
    Max(Case When CF.FieldId = 2 Then FieldValue End) as Descrption
From
    Container C
    Left Join ContainerField CF on C.ID = CF.ContainerID

Group By
    C.ID, 
    C.Name
Order By 
    C.ID
)

输出:

CONTAINERID     NAME        DESCRPTION
1               Container1  Container1 Desc
2               Container2  Container2 Desc
3               Container3      

答案 3 :(得分:0)

你似乎需要一个left join

select c.id, c.name, cf.FieldValue
from Container c join
     ContainerField cf
     on cf.ContainerId = c.id and cf.FieldId = 2;

当然,你问题中的数据有点误导。我假设name列旨在来自Container表。

答案 4 :(得分:0)

我认为这就是你所追求的目标:

SELECT t1.ContainerId, t1.FieldValue, t2.FieldValue
FROM ContainerField t1
LEFT JOIN ContainerField t2 ON t1.ContainerId = t2.ContainerId 
      AND t1.FieldId = 1 and t2.FieldId = 2

编辑(SQL Fiddle):

SELECT DISTINCT t1.ContainerId,
(
   SELECT t2.FieldValue FROM ContainerField t2
   WHERE t2.FieldId = 1 AND t1.ContainerId = t2.ContainerId

) AS [Name],
(
   SELECT t3.FieldValue FROM ContainerField t3
   WHERE t3.FieldId = 2 AND t1.ContainerId = t3.ContainerId
) AS [Desc]
FROM ContainerField t1