sql - 在 SQL 中编写或替换双 for 循环(表遍历另一个表遍历)的有效方法
问题描述
所以现在我有两个表,即dbo.DEMAND
and dbo.SUPPLY
,其中包含包括bidderID
/ vendorID
、itemID
、quantity
、bidPrice
/sellPrice
等列。现在我想定期(通过使用 SQL Server 的代理完成)并自动匹配符合条件的行(这是我的问题)指定下面,按 排序publishTime
,并将一些信息转移到另一个表中dbo.DEAL
。
我目前正在做的方式是首先declare @temp table
将所有内容dbo.DEMAND
插入@temp
. 然后我使用WHILE
遍历dbo.DEMAND
表,对于每一行在SELECT TOP 1 XXX FROM
满足特定条件dbo.SUPPLY
时使用表。最后,当遍历完成时(变为 0,或者在表中找不到匹配项时),我在表中的行中重新开始遍历下一个行。更具体地说,我的目标是找到所有满足的匹配:DELETE
@temp
dbo.SUPPLY
@temp.Quantity
dbo.SUPPLY
{1. @temp.ItemID = SUPPLY.ItemID;
2. @temp.Bid > SUPPLY.Price;
3. @temp.LowestDegre > SUPPLY.DegreeN.}
一个接一个,首先遍历@temp
由 排序的DEMAND.PublishTime
,当找到一个匹配时做:
{1. For the 2 rows (in the two tables), DELETE both rows and the 1 corresponding row in dbo.DEMAND if Quantities are equal, or,
DELETE the row with smaller Quantity, and SUBTRACT the Quantity in the row with larger Quantity with the smaller one;
2. Add a row in the DEAL table, containing BuyerID, SellerID, ItemID, BidPrice, etc;
3. Redo the MATCH procedure.}
基本上在我看来,这种方式与 C++ 中的双循环相同。但是,我听说 SQL 擅长处理集合(大概就像我们总是希望在 MATLAB 中进行矩阵运算),并且逐行遍历确实需要很长时间。如何优化我当前使用的算法?
示例代码:
DECLARE @temp TABLE
(
buyer char(20),
bid float,
quantity smallint,
item char(20),
lowestnew decimal(18,2),
lowestrep decimal(18,2),
pubtime date
);
INSERT INTO @temp(buyer,bid,quantity,item,lowestnew,lowestrep,pubtime)
SELECT BuyerID,Bid,Quantity,ItemID,LowestDegreeNew,LowestReputation,PublishTime FROM DEMAND
ORDER BY PublishTime;
DECLARE @flag int
SET @flag = 0
DECLARE @seller char(20), @buyer CHAR(20), @item char(20), @lowestdegree decimal(18,2), @lowestrep decimal(18,2)
WHILE EXISTS (SELECT buyer, item, lowestnew, lowestrep FROM @temp)
BEGIN
SET @flag = 1
SELECT @buyer = buyer, @item = item, @lowestdegree = lowestnew, @lowestrep = lowestrep FROM @temp
DECLARE @price FLOAT, @quantity SMALLINT
IF EXISTS (select Price, SellerID, Quantity from SUPPLY, SELLER where SellerID = ID and @lowestdegree >= DegreeNew and @lowestrep>=Reputation order by Price)
BEGIN
SELECT TOP 1 @price=Price, @seller = SellerID, @quantity = Quantity FROM SUPPLY, SELLER WHERE SellerID = ID AND @lowestdegree >= DegreeNew AND @lowestrep>=Reputation
IF ((SELECT Quantity FROM DEMAND WHERE SellerID = @seller AND ItemID = @item AND (DegreeNew >= @LowestDegreeNew) AND (Price <= @bid)) IS NOT NULL)
BEGIN /* TRANSFER INTO NEW TABLE */
脚注:我知道这可以很容易地通过在前端编写简单的 C# 或 Python 代码来实现,但我想看看是否可以单独在数据库系统中执行此操作。
解决方案
TLDR:不,您必须继续使用循环结构。
我去过那儿。“最近一天”的加入使得很难使用一个好的集合操作。这就是为什么。考虑那些具有相同 equijoin 属性(vendor=item 等)的记录:
Supply: Day 1
Supply: Day 2
Demand: Day 2
在这种情况下,由于时差,您可能希望将 Supply Day 2 与 Demand Day 2 结合起来。但如果是这样:
Supply: Day 1
Supply: Day 2
Demand: Day 2
Demand: Day 3
您可能需要 Supply Day 1 - Demand Day 2 和 Supply Day 2 - Demand Day 3。
这意味着每一行都以一种不容易的方式依赖于其他行(即:滞后/领先窗口函数不会拯救你)。
这是您需要游标/while 的罕见情况之一。
推荐阅读
- python - 如何使用 Pyro4 在不同主机上实现多处理
- flutter - flutter:如何获取ListWheelChildLoopingListDelegate中选中项的索引?
- r - 基于R中包含变量名称的对象的子集数据框
- python - 如何从python中的字符串中删除(真正的)最后一个字符?[即不创建新参考]
- php - PHP使用函数写入文件
- python - Pygame如何处理状态
- java - 有没有办法通过流或其他方式对具有 2 个类的数组列表进行排序?
- c - 如何接受用户的全部和部分输入字符串?
- python - 如何制作一个不是矩形且没有 pygame 绘图命令的墙。(如果可能)
- android - 将颤振升级到 1.20 后,文本字段在较低的 Android API 设备上出现错误