SQL,循环还是不循环?

时间:2014-04-15 06:16:37

标签: sql sql-server sql-server-2012

问题故事如下:

考虑一个程序来管理每个客户的余额限制的银行账户 {table Customerstable Limits}每个Customer.id的位置都有一个限制记录
然后客户说要存储限制更改的历史记录,这不是问题,因为我已经有Limit的日期列,但需要更改active/latest limits的查看查询

之前:客户限制为1比1,因此一个简单的选择完成了工作 现在:它会显示所有Limits的记录,这意味着每个客户的多条记录,我只需要最新的限制,所以我想到了这样的伪代码

foreach( id in Customers)
{
  select top 1 *
  from Limits
  where Limits.customer_id = id
  order by Limits.date
}

但是在查看类似问题的同时,我遇到了像
这样的东西 "95% of the time when you need a looping structure in tSQL you are probably doing it wrong"-JohnFx

"SQL is primarily a set-orientated language - it's generally a bad idea to use a loop in it."-Mark Bannister

任何人都可以确认/解释为什么循环错误?在上面解释的问题中,我需要循环的错误是什么?

提前致谢

更新:我的解决方案 根据TomTom的回答&建议链接here,在Dean亲切地回答代码之前,我想出了这个

SELECT *
FROM Customers c
LEFT JOIN Limits a ON a.customer_id = c.id
  AND a.date = 
    (
       SELECT MAX(date) 
       FROM Limits z 
       WHERE z.customer_id = a.customer_id
    )

以为我会分享:>

感谢您的回复,
快乐的编码

4 个答案:

答案 0 :(得分:1)

这会吗?

;with l as (
  select *, row_number() over(partition by customer_id order by date desc) as rn
  from limits
)
select *
from customers c
left join l on c.customer_id = l.customer_id and l.rn = 1

答案 1 :(得分:1)

我假设之前(即在实现历史记录功能之前),您必须更新Limits表。现在,为了实现历史记录功能,您已开始插入新记录。这不会引发数据库和代码的很多变化吗?

而不是插入新记录,如何保持原始功能并创建一个新表格Limits_History,它会在更新之前存储Limits表中的所有旧值?然后,如果要显示历史记录,您需要做的就是从此表中获取记录。这不会导致现有SP和代码发生任何变化,因此不会出错。

要在Limits_History表格中插入记录,您只需创建AFTER TRIGGER并使用deleted魔术表即可。因此,您无需担心调用SP或其他东西来维护历史记录。触发器将为您执行此操作。触发器的好例子是here

希望这有帮助

答案 2 :(得分:0)

这是错的。您可以通过使用子查询来限制客户和限制来执行相同的操作,该子查询限制为最近的限制记录。

这在概念上类似于Most recent record in a left join

中提出的查询

您可能必须在2个连接中执行此操作 - 获取最近的日期,然后获取日期限制。虽然这可能看起来很复杂 - 这是一个初学者的问题,当你的sql语句达到2个打印页面时会说话复杂;)

现在,对于操作系统,表设计被破坏 - 限制应该包含mos trecent限制,LimitHistory表包含历史(或所有)条目,允许快速检索CURRENT限制(这将是适用于所有交易),没有历史的开销。您设置的表格设计假定所有限制都是相同的 - 这可能是报告数据仓库的事实(事实),但由于历史记录未进行交易,因此对于交易系统而言是错误的。

答案 3 :(得分:0)

确认循环错误的原因正好在您问题的引用部分中 - SQL是一种面向集合的语言。 这意味着当您处理集合时,没有理由循环遍历单行,因为您已经拥有了要处理的数据的“结果”(集合)。 那么你正在做的工作应该在行集上完成,因为否则你的选择是错误的。

话虽如此,当然还有在SQL中完成循环的情况,如果在数据上,通常会通过游标完成,或者如果计算内容,则通过while循环完成。 (通常,例外总是会改变)。 但是,正如引号中所提到的,通常当你想要使用循环时,你不应该(它的性能很差)或者你在应用程序的错误部分做逻辑。

基本上 - 它类似于面向对象的语言如何处理对象和对所述对象的引用。基于集合的语言可用于 - 以及数据集。

SQL基本上是以这种方式运行 - 将关系数据查询到结果集中 - 因此在使用该语言时,您应该让它做它能做的事情并对其进行处理。就像它是Java或任何其他语言一样。

相关问题