2016-09-15 19 views
0

现在,我正在构建一个巨大的db2查询,在这里我从很多表中选择大量数据(10个表以上的LEFT OUTER JOIN)。大多数数据都很好地选择和工作正常,但其中大部分是非常简单的DB2 SQL仅通过子查询才能获得第一个匹配

但有一张桌子给我一点头痛。如果我们只是在查看SQL和结果时,我们不从这张表中选择,它看起来有点像这样:(由于数据的性质,我不能从我的SQL中给出示例)

SQL 1:

SELECT Person.Name, Date.NameOfDate, Location.City 
FROM Person LEFT OUTER JOIN 
Date ON Person.Id = Date.PersonId LEFT OUTER JOIN 
Location ON Date.LocationId = Location.Id 
WHERE Person.IsAlive = True 

结果1:

Name - NameOfDate - City 
Peter - Anna - Athen 
Peter - Caroline - Washington 
Simone - Carl - Athen 

现在我有一个表(姑且称之为 '注释')。这张表格有一些关于城市的额外信息。每个城市可以有多行。例如:

SQL 2:

SELECT Location.City, Comment.Text, Comment.SortingId, Comment.TypeOfData 
FROM Location LEFT OUTER JOIN 
Comment ON Location.Id = Comment.LocationId 

结果2:

City - Text - SortingId - TypeOfData 
New York - Do not read this - 1 - 777 
Washington - This text is irrelevant - 1 - 555 
Washington - Make sure you visit the White House - 2 - 777 
Washington - On saturdays there is a market near the docks - 3 - 777 
Athen - Bring translator - 1 

我的问题是,我需要在SQL 1检索Comment.Text,但只具有最低SortingId行,其中TypeOfData是777.结果应该是这样的:

Name - NameOfDate - City - Text 
Peter - Anna - Athen - Bring translator 
Peter - Caroline - Washington - Make sure you visit the White House 
Simone - Carl - Athen - Bring translator 

我已经设法做出的最接近的事情得到这个数据如下:

SELECT Person.Name, Date.NameOfDate, Location.City, Comment.Text 
FROM Person LEFT OUTER JOIN 
Date ON Person.Id = Date.PersonId LEFT OUTER JOIN 
Location ON Date.LocationId = Location.Id LEFT OUTER JOIN 
(SELECT Comment.Text FROM Comment ORDER BY Comment.SortingId FETCH FIRST 1 ROWS ONLY) AS Comment ON Location.Id = Comment.LocationId 
WHERE Person.IsAlive = True 

但正如一些人可能已经注意到,这并不给我任何结果。子选择将返回纽约行,然后它会过滤LocationId,它将删除纽约,不留任何东西

任何其他想法?

编辑:

的评语表没有任何独特的ID字段。你可以有两行,唯一不同的是SortingId,但是相同的SortingId可以用在许多行中,例如SortingId可能是1成两排,不同LocationId

+0

所以你没有得到你所查询的任何行?甚至不是华盛顿和雅典? –

+0

如果只需要一列,请尝试关联的子查询。 – Serg

+0

@Bhavesh - 正确。原因是Erwin Smout提到的。我只得到查询中的前1名,但在这种情况下,前1名将是纽约。然后当我在查询之外有一个WHERE看着LocationId它将不会返回任何 –

回答

0

你可以试着加入位置的表里面的子查询与评论,像这样

(SELECT Comment.Text FROM Locat LEFT OUTER JOIN 
Comment ON Locat.Id = Comment.LocationId 
WHERE Locat.City = Location.City 
ORDER BY Comment.SortingId 
FETCH FIRST 1 ROWS ONLY) 
+0

我相信这不会从我所能看到的。它与主查询没有任何关联。它不会根据主查询的当前行选择任何内容。这将导致子查询再次总是返回第一行,而不管它正在处理哪一行。在这种情况下,子查询将始终返回纽约。或者我错过了什么? –

+0

实际上,在子查询的“WHERE Locat.City = Location.City”中,Location.City来自主查询。 –

+0

不幸的是,这是行不通的。子查询不知道位置,因为它位于子查询的范围之外 –

0

你的SELECT查询生成具有1行的最低SortingId 表整体。你大概想要的是在手头的城市中排名最低的1排,排名为

将WHERE子句添加到应用此条件的SELECT子查询中。可能是这种情况(事实上,我认为很可能是这种情况),无法写入此条件,因为您的Location.Id在该WHERE子句内是“超出范围”。

如果是这样,删除订单,并从子查询FETCH条款,并恢复在

AND NOT EXISTS (
    SELECT * 
    FROM Comment AS SECONDCOMMENT 
    WHERE cities-the-same AND SECONDCOMMENT.SortingId > Comment.SortingId 
) 
+0

我不确定你在哪里指的是什么城市 - 相同? –

+0

你对你的假设是正确的。子查询只会返回一行(纽约),但由于这个结果不符合我所搜索的LocationId,它不会返回任何内容。另外正如你所提到的,我不能但子查询内的条件,因为子查询不知道位置。如果这是可能的,那么这将是一个简单的修复方法 –

+0

cities--与表示该条件的一些正确和适当的SQL语法的占位符相同。 (在大的NOT EXISTS中,我写了'>',但实际上它应该是'<')。 –

0

你可以使用一个DENSE_RANK()解析函数,该函数的形式,其中在“最”所需的过滤。您的样本数据似乎有点不一致(有雅典没有Comment.TypeOfData值),但尝试沿着这些路线的东西:

SELECT * FROM (
    SELECT 
    l.city, c.text, c.sortingid, c.typeofdata , 
    DENSE_RANK() OVER (PARTITION BY c.locationid ORDER BY c.sortingid) rnk 
    FROM location l 
    LEFT JOIN comment c 
    ON l.id = c.locationid 
    AND c.typeofdata = 777 
) t 
WHERE rnk = 1 

PS。你的问题明确要求子选择,在这个解决方案中的一个子选择,虽然可能不是你认为它可能的地方。

0

从9.7开始,DB2就可以通过窗口函数来实现这一点。

具体FIRST_VALUE。它的工作原理是这样的:

SELECT Location.ID, Location.City, C.Text, C.SortingID, C.TypeOfData 
FROM Location 
LEFT OUTER JOIN (
    SELECT DISTINCT LocationID 
      FIRST_VALUE(Text) OVER (PARTITION BY LocationID ORDER BY SortingId) as Text, 
      FIRST_VALUE(SortingId) OVER (PARTITION BY LocationID ORDER BY SortingId) as SortingID, 
      FIRST_VALUE(TypeOfData) OVER (PARTITION BY LocationID ORDER BY SortingId) as Typeofdata 
    FROM Comment 
) AS C ON Location.Id = C.LocationId 

这将返回1行每个ID,每个城市

+0

如果有多个注释,那实际上会返回一个城市的多行,不是吗?尽管它们都包含相同的值。 – mustaccio

+0

@mustaccio - 刚编辑修复。 – Hogan

+0

我不认为最新版本可以使用(即使你添加了缺少的“FROM”)。你仍然从'Comment'返回所有行。 – mustaccio

0

试试这个

SELECT Person.Name, Date.NameOfDate, Location.City, tmp.Text 
    FROM Person 
    LEFT OUTER JOIN Date ON Person.Id = Date.PersonId 
    LEFT OUTER JOIN Location ON Date.LocationId = Location.Id 
    LEFT OUTER JOIN LATERAL(
    select Text FROM Comment 
    where Location.Id = Comment.LocationId and Comment.TypeOfData=777 
    order by Comment.SortingId 
    fetch first rows only 
    ) tmp on 1=1 
    WHERE Person.IsAlive = True