【问题标题】:Database query while looping循环时查询数据库
【发布时间】:2011-07-20 16:21:44
【问题描述】:

我 99% 确定这个问题已经被问了 100 次,但我在 SO 上找不到任何关于最佳方法的信息。

我有一个名为 People 的表,然后是一个名为 Jobs 的表,其中存储了他们所有的就业历史。

在创建报告、仪表板等时经常出现,我们希望在其中列出每个人及其最近的 3 个工作(例如):

约翰·史密斯

  • 某公司,4/3/2011-5/14/2011
  • 另一家公司,3/12/2010-4/1/2011
  • 不同的公司,2009 年 8 月 1 日-2010 年 1 月 4 日

莎莉史密瑟斯

  • 某公司,4/3/2011-5/14/2011
  • 另一家公司,3/12/2010-4/1/2011
  • 不同的公司,2009 年 8 月 1 日-2010 年 1 月 4 日

等等

一些 VBish 的伪代码:

SELECT PersonID, Name FROM People

Do While datareaderPeople.Read()
   Response.write(datareaderPeople("Name")
   'SELECT TOP 3 PersonID, JobID, CompanyName, OtherFields FROM Jobs WHERE PersonID = datareaderPeople("PersonID") ORDER BY SomeDateField
   Do While datareaderJobs.Read()
       Response.write(datareaderJobs("CompanyName"))
   End While
End While

如您所见,我们目前正在执行另一个查询,以便在我们循环访问人员时获取每个人的工作。有一个更好的方法吗?这种方式似乎效率低下,并且会创建大量的数据库查询。

或者如果有人可以指出我之前提出的这个问题,那也很好。

谢谢。

编辑:我使用上述方法是因为我需要能够对我返回的每个 Jobs 行的 Jobs 字段执行操作。比如格式化日期、加粗公司名称等。仅仅返回 1 大行并将 Jobs 字段组合成 1 个大字符串是行不通的。

【问题讨论】:

  • 您可以对表执行连接,这正如您想象的那样非常低效(1000 人结果意味着 1001 个 SQL 查询)。
  • jobID 是每个人的增量。那么,Jobs 的关键是 PersonID,JobID?如果是这种情况,您可以使用简单的连接并避免使用 Quassnoi 的子查询。编辑:也许我错了,从前 3 个 id 中选择会很困难......获得前 3 个会很容易。
  • @can poyrazoğlu - 加入只会为每个人返回 1 行,不是吗?我需要能够对 Jobs 行中的各个字段进行处理。 (见问题编辑)谢谢。

标签: asp.net sql database


【解决方案1】:

假设SQL Server 2005 或更高:

SELECT  *
FROM    people p
OUTER APPLY
        (
        SELECT  TOP 3 *
        FROM    job j
        WHERE   j.personId = p.id
        ORDER BY
                j.applicationDate DESC
        ) j

或者这个:

SELECT  *
FROM    (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY j.appicationDate DESC) AS rn
        FROM    people p
        LEFT JOIN
                job j
        ON      j.personId = p.id
        ) q
WHERE   rn <= 3

【讨论】:

  • 那么这些对我的应用程序代码意味着什么?例如,如果我使用 vb.net 或 c#,如何循环返回的行?我在问题中使用该方法的主要原因是因为我希望能够对 Jobs 行中的字段进行处理。也许格式化日期字段,加粗公司名称文本等。这些方法不会只为每个人返回 1 行,而不是让我访问工作行中的各个字段吗?谢谢。
【解决方案2】:

我建议您执行以下操作,这将只是 2 个数据库调用

SELECT PersonID, Name FROM People
SELECT PersonID, JobID, CompanyName, OtherFields FROM Jobs

Do While datareaderPeople.Read()
   Response.write(datareaderPeople("Name")
   Filter Jobs records data with DataView using RowFilter = "PersonID = " + datareaderPeople("PersonID")

   Do While FilteredRows.Read()
       Response.write(FilteredRows("CompanyName"))
   End While
End While

【讨论】:

  • 对在应用程序中过滤行的普遍看法似乎是不要这样做。在这种情况下,是否使用过滤行是更好的选择,因为它可能会阻止为 1 个页面加载进行数百次数据库调用?
  • 对不起,我没明白你的问题的意思
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 1970-01-01
  • 2020-06-25
相关资源
最近更新 更多