我希望有人可以帮我解决这个问题。我为这个冗长的场景和问题提前道歉。
我在SQL Server 2000中有三个表:Vendors
,Imports
和ImportsStatus
。
供应商每月发送交易,当处理它们时,将在Imports中为所有供应商创建单个记录,并且还在ImportsStatus表中创建EACH供应商的单个记录。
ImportsStatus与ImportID
上的Imports相关。
供应商与ImportsStatus
上的ImportsStatus相关。VendorID
= Vendors.ID
。
我正在尝试构建一个单独的select语句,我可以创建一个视图,显示每个导入的所有可能供应商的列表,无论供应商是否已经导入。另外,我想显示给定ImportNo的整个导入是否已完成。例如,对于ImportNo
3,仅导入了VendorIDs
1和2(并且VendorID
2甚至没有完成),但我希望看到VendorID
3 in该列表尚未完成,因为ImportDate
2的ImportNo
位于VendorID
3 StartDate
和EndDate
间隔内(即我们应该期待导入为那个月VendorID
3。同样,对于VendorID
3的每个ImportNo
,我希望看到0表示导致该ImportNo
的所有供应商的导入都不完整。
我对查询进行了大量修改(一个原因是我会开始看到VendorID 1的多个条目,因为它在ImportNo
3的导入表及其StartDate
中并且EndDate
也围绕ImportNo 3的ImportDate
)。我终于想出了一个看起来和感觉非常笨重和错误的查询。我希望有人可以帮我告诉我如何优化这个查询。
提前致谢。
CREATE TABLE Vendors (
ID INT IDENTITY(1, 1) NOT NULL,
Name VARCHAR(50) NOT NULL,
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL
)
CREATE TABLE Imports (
ImportNo INT NOT NULL,
ImportDate DATETIME NOT NULL
)
CREATE TABLE ImportsStatus (
ImportNo INT NOT NULL,
VendorID INT NOT NULL,
UserName VARCHAR(50) NOT NULL,
DateProcessed DATETIME NOT NULL,
Completed BIT NOT NULL
)
INSERT INTO Vendors (Name, StartDate, EndDate) VALUES ('ABC', '1/1/1800', '9/9/9999')
INSERT INTO Vendors (Name, StartDate, EndDate) VALUES ('DEF', '12/1/15', '9/9/9999')
INSERT INTO Vendors (Name, StartDate, EndDate) VALUES ('GHI', '12/1/15', '9/9/9999')
INSERT INTO Imports (ImportNo, ImportDate) VALUES (1, '10/1/15')
INSERT INTO Imports (ImportNo, ImportDate) VALUES (2, '11/1/15')
INSERT INTO Imports (ImportNo, ImportDate) VALUES (3, '12/1/15')
INSERT INTO ImportsStatus (ImportNo, VendorID, UserName, DateProcessed, Completed) VALUES (1, 1, 'me', '10/5/15', 1)
INSERT INTO ImportsStatus (ImportNo, VendorID, UserName, DateProcessed, Completed) VALUES (2, 1, 'me', '11/6/15', 1)
INSERT INTO ImportsStatus (ImportNo, VendorID, UserName, DateProcessed, Completed) VALUES (3, 1, 'me', '12/4/15', 1)
INSERT INTO ImportsStatus (ImportNo, VendorID, UserName, DateProcessed, Completed) VALUES (3, 2, 'me', '12/5/15', 0)
-- Query that I want to optimize
SELECT ImportNo, ImportDate, CAST(MAX(CAST(Completed AS INT)) AS BIT) AS
Completed, ID AS VendorID, Name,
CASE WHEN (SELECT COUNT(*) FROM Vendors
WHERE StartDate <= t.ImportDate AND EndDate > t.ImportDate) -
(SELECT COUNT(*) FROM Vendors p INNER JOIN ImportsStatus s ON p.ID = s.VendorID
WHERE s.ImportNo = t.ImportNo AND s.Completed = 1) = 0 THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END AS BatchCompleted
FROM
(
SELECT CASE WHEN i.ImportNo IS NOT NULL THEN i.ImportNo ELSE
(SELECT TOP 1 ImportNo FROM Imports
WHERE v.StartDate <= ImportDate AND v.EndDate >ImportDate)
END AS ImportNo,
CASE WHEN i.ImportNo IS NOT NULL THEN i.ImportDate ELSE
(SELECT TOP 1 ImportDate FROM Imports
WHERE v.StartDate <= ImportDate AND v.EndDate > ImportDate)
END AS ImportDate,
CASE WHEN i.ImportNo IS NOT NULL THEN s.Completed ELSE CAST(0 AS BIT) END AS Completed,
v.ID,
v.Name
FROM Vendors v
LEFT JOIN (ImportsStatus s INNER JOIN Imports i on s.ImportNo = i.ImportNo)
ON s.VendorID = v.ID
) t
WHERE ImportNo IS NOT NULL
GROUP BY ImportNo, ImportDate, ID, Name
答案 0 :(得分:1)
编辑:如果你不能在2000年的聚合函数上使用OVER子句,以下应该完成同样的事情。对不起,我错过了2000的要求,不幸的是你需要一个子查询或派生表。完成此类问题的最快方法取决于数据,但我喜欢仅在派生表中对密钥进行分组,然后加入到该表中,我认为这对于更大的数据集表现更好。
select i.ImportNo,
i.ImportDate,
coalesce(i_s.Completed, 0) as Completed,
v.ID VendorID,
v.Name,
case when grp.Completed = grp.Total then 1
else 0
end as BatchCompleted
from Imports i
left join Vendors v on i.ImportDate between v.StartDate and v.EndDate
left join ImportsStatus i_s on i.ImportNo = i_s.ImportNo and v.ID = i_s.VendorID
join (select i.ImportNo,
sum(cast(i_s.Completed as int)) Completed,
count(v.ID) Total
from Imports i
left join Vendors v on i.ImportDate between v.StartDate and v.EndDate
left join ImportsStatus i_s on i.ImportNo = i_s.ImportNo and v.ID = i_s.VendorID
group by i.ImportNo
) grp on grp.ImportNo = i.ImportNo
我相信以下查询可能是您正在寻找的更容易阅读的版本:
select i.ImportNo,
i.ImportDate,
coalesce(i_s.Completed, 0) as Completed,
v.ID VendorID,
v.Name,
iif(sum(cast(i_s.Completed as int)) over (partition by i.ImportNo) = count(v.ID) over (partition by i.ImportNo), 1, 0) as BatchCompleted
from Imports i
left join Vendors v on i.ImportDate between v.StartDate and v.EndDate
left join ImportsStatus i_s on i.ImportNo = i_s.ImportNo and v.ID = i_s.VendorID
这里的想法是使用分区的总和/计数而不是子查询来确定批次是否完成。它还使用LEFT JOIN
来确保包含每个导入。我重新排序并在最后放置ImportsStatus以防止您遇到重复的问题。