获取记录关系1 --- N可以为空并在子表上过滤

时间:2013-01-27 10:01:10

标签: sql oracle

我想从两个与fk链接的表中获取记录。此fk可以为null,子表必须具有过滤器。 我用简单的例子来解释它。

Table Poet
IdPoet Number(5) 
NameVarchar2(250)

Table Poem 
IdPoem Number(5) 
IdPoet Number(5) FK 
Language Number(1) 
Text Varchar2(2000)
  

FK是Poet和Poem的关系   诗人-1 -------------- N0 ---诗

     

Poem.IdPoet可以为null。

我需要从诗人那里得到没有诗歌的所有记录,以及诗歌用语言= 1或语言= 2的诗人。语言1比2更具限制性。这意味着如果有一个诗人有2首诗(一个写在语言1上,另一个写在语言2上)必须只显示语言1的记录。

    SELECT *
    FROM POET, POEM
    WHERE POET.IDPOET = POEM.IDPOET(+)
    AND
    (
    (POEM.LANGUAGE IS NOT NULL AND POE.LANGUAGE = 1) OR
    (POEM.LANGUAGE IS NOT NULL AND POE.LANGUAGE = 2) OR
    (POEM.LANGUAGE IS = 1) OR
    (POEM.LANGUAGE IS = 2)
    )

这个选择显示没有诗歌的诗人,他们在语言1上有1首诗或在诗歌2上有1首诗。问题是当诗有2首诗时,一首是语言1而另一首是语言2,那么显示2条记录,我想只显示语言1上的诗歌记录,因为它比2更具限制性。

3 个答案:

答案 0 :(得分:0)

不确定这是否有效,但想法是创建一个所有诗人的名单,如果他们写了一些东西,他们所有的诗。

Poets-table与诗歌联系在一起,包括所有诗人

select distinct poets.Name,
       coalesce (l1.Text, l2.Text,'NONE') as Poem
  from Poets 
       left join (
         Poems l1
         full join Poems l2 
           on l1.IdPoet = l2.IdPoet
         )
         on Poets.IdPoet = l1.IdPoet

where 1l.Language = 1 and l2.Language=2

(未测试的)

然而,如果一位诗人用一种语言写了不止一首诗,就会显示出来。我不知道这是不是你想要的。

答案 1 :(得分:0)

您可以使用Oracle的ROW_NUMBER()分析函数轻松完成此操作:

SELECT Name, Text FROM (
  SELECT PT.Name, PM.Text, ROW_NUMBER() OVER (PARTITION BY PT.IdPoet ORDER BY PM.Language) RN
  FROM POET PT
  LEFT JOIN POEM PM ON (PT.IdPoet = PM.IdPoet)
  WHERE PM.Language IS NULL OR PM.Language IN (1, 2)
) WHERE RN = 1

请注意,如果单个诗人的语言1中有多首诗歌,那么它只会选择从数据库中首先返回的诗歌。您可以在分区子句中向ORDER BY添加另一个字段,以便根据您的需要首先按诗名等进行排序。

SQL Fiddle


编辑:此外,如果您想要alzaimar提出的相同行为(即显示语言1中的所有诗歌),您可以使用DENSE_RANK()函数代替{{1 }}

答案 2 :(得分:0)

如果您想使用最低语言值选择每首诗歌的信息 对于每一位诗人,以及没有诗歌的诗人,这个问题应该做:

SELECT * FROM Poet P
LEFT JOIN Poem ON Poem.IdPoet = P.IdPoet
where Poem.Language IS NULL
OR Poem.Language =
    (SELECT MIN(Language) As L1
     FROM Poem
     WHERE Poem.IdPoet = P.IdPoet
     GROUP BY Poem.IdPoet)

这里语言的最低值假定为1,并且查询也将使用高于2的语言值。