0

我正在用 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 查询以在不添加更多循环的情况下拉回这些数据有建议?这已经很长了,所以我会在这里退出。如果您需要更多信息,请询问...

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

4

2 回答 2

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。

于 2011-12-07T14:06:00.333 回答
0

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

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

粗鲁但有效。如果我想出一种更巧妙的方法,我会回来发布它。

玩得开心!!

于 2011-12-27T17:39:05.630 回答