如何编写T-SQL以使用原始数据集返回工具提示的数据?

时间:2011-12-06 19:45:48

标签: sql-server tsql sql-server-2008r2-express

我正在使用T-SQL编写一个SP,以便从SQL Server 2008 R2上的数据库表中存储的测试数据中恢复“首次传递率”指标。我编写了SP来返回应用程序中图形化的基本数据,但我想添加工具提示,以便在用户将鼠标悬停在图形片段上时提供特定时间段的详细信息。

注意 - 我不是在这里询问如何处理UI部分,而是如何获取数据。 UI的东西,我稍后会处理......

这是一个用于存储原始数据的简化模式:

CREATE TABLE [dbo].[TestRecords](
    [TestRecordID] [int] NOT NULL,
    [HostName] [varchar](25) NOT NULL,
    [UnitSerial] [varchar](20) NOT NULL,
    [PassFailStatus] [bit] NOT NULL,
    [AssyLineID] [int] NOT NULL,
    [TestDateTime] [datetime] NOT NULL)

这个想法是返回第一次正确构建的单位总数除以构建的单位总数 - 这是第一次通过产量数。我们希望在任意时间段内为任意数量的装配线(AssyLineID)执行此操作。

在这种情况下,'任意'意味着在特定日期每小时或在更长时间内每天...

结果数据集是这样的记录表:

CREATE TABLE [dbo].[FpyValues](
    [FpyValueID] [int] IDENTITY(1,1) NOT NULL,
    [SessionID] [int] NOT NULL,
    [DateTime] [datetime] NOT NULL,
    [AssyLineID] [int] NOT NULL,
    [Fpy] [float] NOT NULL,
    [TotalUnits] [int] NOT NULL,
    [FailedUnits] [int] NOT NULL) 

到目前为止一切顺利,但返回的FPY值并没有太多信息。对于有趣的事件(相对较低或较高的FPY),质量团队想知道他们正在构建什么类型的单位以及用于获得FPY的数量 - 而无需咨询另一份报告。我可以在显示工具提示时返回数据库,但数据不一样。原始数据集考虑了在较早时间段内失败的单位,并且没有(错误地)将其计为当前时间段内的良好单位。

这是我的SP的一个简化版本,用于获取特定日期的每小时FPY:

ALTER PROCEDURE [dbo].[GetHourlyFpy] 
    @ProdLineList VARCHAR(100), 
    @ReportDate DATETIME
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @Fpy FLOAT, @Total FLOAT, @Failed FLOAT
    DECLARE @SessionID INT;
    DECLARE @TempList TABLE
                        (
                            LineID INT
                        );
    DECLARE @LineID VARCHAR(10);
    DECLARE @LineName VARCHAR(16);
    DECLARE @FailedUnits TABLE
                            (
                                UnitSerial VARCHAR(12)
                            );
    DECLARE @Start INT, @End INT, @Current INT;
    DECLARE @StartTime DATETIME, @EndTime DATETIME;

    -- unpack incoming comma-separated list of Production Line IDs into temp table

    -- get session ID to identify results for this session

    -- get the start and end hour values (@Start and @End)

    -- Get the Date part of the incoming DATETIME value (time = 00:00:00.000)

    -- loop through all production lines, creating result records as we go
    WHILE EXISTS(SELECT * FROM @TempList)
    BEGIN
        SELECT TOP 1 @LineID = LineID FROM @TempList;

        -- clear the failed units table
        DELETE FROM @FailedUnits;

        -- set the start time for reporting
        SET @StartTime = (SELECT DATEADD(Hh, @Start, @ReportDate));

        -- loop through all 1-hour periods for the day
        SET @Current = @Start;
        WHILE @Current < @End
        BEGIN
            SET @EndTime = (SELECT DATEADD(Hh, 1, @StartTime));
            SET @Total = (SELECT COUNT(DISTINCT tr.UnitSerial)
                            FROM TestRecords
                            WHERE @StartTime <= tr.TestDateTime 
                                AND tr.TestDateTime < @EndTime
                                AND tr.AssyLineID = @LineID
                                AND (NOT EXISTS
                                    (SELECT UnitSerial FROM @FailedUnits f WHERE tr.UnitSerial = f.UnitSerial)));

            SET @Failed = (SELECT COUNT(DISTINCT tr.UnitSerial)
                            FROM TestRecords tr
                            WHERE @StartTime <= tr.TestDateTime 
                                AND tr.TestDateTime < @EndTime
                                AND tr.PassFailStatus = 0
                                AND tr.AssyLineID = @LineID
                                AND (NOT EXISTS
                                    (SELECT UnitSerial FROM @FailedUnits f WHERE tr.UnitSerial = f.UnitSerial)));

            -- populate the failed units list as needed
            INSERT INTO @FailedUnits
                SELECT DISTINCT tr.UnitSerial 
                    FROM dbo.TestRecords tr
                          LEFT OUTER JOIN
                        @FailedUnits f ON tr.UnitSerial = f.UnitSerial
                    WHERE @StartTime <= tr.TestDateTime 
                        AND tr.TestDateTime < @EndTime
                        AND tr.PassFailStatus = 0
                        AND tr.AssyLineID = @LineID
                        AND f.UnitSerial IS NULL;

            IF (0 = @Total)
                SET @Fpy = 0;
            ELSE
                SET @Fpy = (@Total - @Failed) / @Total;

            INSERT INTO dbo.FpyValues (SessionID, [DateTime], ProductionLine, Fpy, TotalUnits, FailedUnits)
                VALUES(@SessionID, @StartTime, @LineID, @Fpy, @Total, @Failed);

            SET @StartTime = (SELECT DATEADD(Hh, 1, @StartTime));
            SET @Current = @Current + 1;
        END

        -- we're done with this production line 
        DELETE FROM @TempList WHERE LineID = @LineID;
    END

    RETURN @SessionID;
END

我需要一种方法来填充表格,其中包含每个时间段的每个装配线的详细信息,如下所示:

CREATE TABLE [dbo].[FpyUnits](
    [FpyUnitID] [int] IDENTITY(1,1) NOT NULL,
    [FpyValueID] [int] NOT NULL,
    [DateTime] [datetime] NOT NULL,
    [AssyLineID] [int] NOT NULL,
    [UnitType] [varchar](25) NOT NULL,
    [TotalUnits] [int] NOT NULL,
    [FailedUnits] [int] NOT NULL)

注意我需要在保存详细记录之前创建主/父记录并将其保存到磁盘,因此我有外键值(FpyValueID)。

我可以想象的一种方法是改变我从详细记录中计算原始数据和SUM数据的方式,以计算整体FPY值。我还可以看到我可能需要使用GROUP BY指令来获取详细信息值。

是否有人建议如何构建SQL查询以在不添加更多循环的情况下提取此数据?这已经很久了,所以我会在这里放弃。如果您需要更多信息,请询问......

提前感谢任何想法/帮助, 戴夫

2 个答案:

答案 0 :(得分:0)

在这里,我对你的第一个要求进行了拍摄:

返回第一次正确构建的单位总数除以构建的单位总数 - 这是第一次通过产量数。

SELECT COUNT(TestRecordID) as UnitsPassed,CAST(CAST(COUNT(TestRecordID) AS DECIMAL(6,3)) / (SELECT COUNT(TestRecordID) FROM TestRecords) AS DECIMAL(6,3)) as FirstPassYield
FROM TestRecords
WHERE PassFailStatus = 1 AND testDateTime > '12/06/2011' AND testDateTime < 12/07/2011'

可能有一种更有效的方法来处理CAST。

答案 1 :(得分:0)

这个问题太长,包含太多不必要的信息。我选择发布我为解决问题所做的工作,而不仅仅是删除它,以防有人有足够的业余时间来实际阅读问题和答案......

将从WCF服务调用此SP,结果数据集将从服务返回到客户端。因此,不需要一次完成所有事情。我打算做的是在第二遍中使用在第一遍中创建的内存表来创建详细记录。会话ID返回给WCF服务,然后WCF服务读取记录集,将数据返回给客户端并删除数据库中的工作记录。

粗暴但有效。如果我想出一个更加流畅的方式,我会回来发布它。

玩得开心!!