DB2 SQL join仅通过subselect

时间:2016-09-15 09:21:11

标签: sql database join db2 subquery

现在我正在构建一个巨大的db2查询,我从很多表中选择了大量数据(10+表上的LEFT OUTER JOIN)。大多数数据都经过精心挑选并且工作正常,但其中大部分都非常简单

但有一张桌子让我有点头疼。如果我们只是在查看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

5 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

您的SELECT子查询生成一个表,其中包含一行,其中SortingId 整体最低。您可能想要的是具有最低SortingId 的1行,用于手头的城市

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

如果是这样,请从子查询中删除ORDER和FETCH子句,并在" outermost"中恢复所需的过滤。在哪里以

的形式
AND NOT EXISTS (
  SELECT * 
  FROM Comment AS SECONDCOMMENT 
  WHERE cities-the-same AND SECONDCOMMENT.SortingId > Comment.SortingId
  )

答案 2 :(得分: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。您的问题明确要求进行子选择,并且在此解决方案中, 是一个子选择,尽管可能不是您认为可能的位置。

答案 3 :(得分: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

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

答案 4 :(得分: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