查询可能的选择和现有交易

时间:2015-12-28 01:12:09

标签: sql sql-server

我希望有人可以帮我解决这个问题。我为这个冗长的场景和问题提前道歉。

我在SQL Server 2000中有三个表:VendorsImportsImportsStatus

供应商每月发送交易,当处理它们时,将在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 StartDateEndDate间隔内(即我们应该期待导入为那个月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

1 个答案:

答案 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以防止您遇到重复的问题。