简体   繁体   中英

How to get comparing records from the same table in SQL Server 2014?

I have a table that shows the entry and exit of items into the warehouse. The Camera 1 and Camera 2 document the entry time and exit time respectively of that item. The cameras then classify the item as it enters and leaves the checkpoint with the help of lasers. Eg: Big box: Class 5, Medium Box: Class 3, Small Box: Class 2.

Sometimes, the cameras classification doesn't match each other. Eg: Classification at entry can be Medium box and on exit can be Small box.

I need to find the number of transactions where the class didn't match for the same TransactionDetail and then a percentage of those class mismatches against all the transaction for a certain time range.

My table looks somewhat like this:

---------------------------------------------------------------------------
| AVDetailID | TransDetailID | AVClassID | CamID | CreatedDate            |
---------------------------------------------------------------------------
| 20101522   | 54125478      | 5         | 1     | 2017-05-08 10:15:01:560|
| 20101523   | 54125478      | 5         | 2     | 2017-05-08 10:15:01:620|
| 20101524   | 54125479      | 3         | 1     | 2017-05-08 10:15:03:120|
| 20101525   | 54125479      | 2         | 2     | 2017-05-08 10:15:03:860|
| 20101526   | 54125480      | 4         | 1     | 2017-05-08 10:15:06:330|
| 20101527   | 54125480      | 4         | 2     | 2017-05-08 10:15:06:850|
---------------------------------------------------------------------------

So, in the above case the class changes from 3 to 2 in record 3 and 4. That is one transaction where the class changed. I need to get a percentage of all transactions that where the class changed between each cameras.

The code I've used so far is below. I just need to find a way to get a percentage of the total Transactions.

DECLARE @MinDate DATE = '20170406',
        @MaxDate DATE = '20170407';

SELECT  COUNT(tdBefore.TransDetailId) TD
        --,SUM((COUNT(*) OVER() / allRecords.Count) * 100) AS DiffPercent

FROM    AVTransDetail AS tdBefore
INNER JOIN AVTransDetail AS tdAfter
    ON tdBefore.TransDetailID = tdAfter.TransDetailID 
    AND tdBefore.ACClassID = 1
    AND tdAfter.ACClassID = 2
CROSS APPLY
(
    SELECT COUNT(*) AS [Count]
    FROM AVTransDetail
    WHERE tdBefore.DateCreated >= @MinDate
        AND tdAfter.DateCreated <= @MaxDate
) AS allRecords
WHERE   tdBefore.AVCClassId <> tdAfter.AVCClassId 
        AND tdBefore.DateCreated >= @MinDate
        AND tdAfter.DateCreated <= @MaxDate

How do I create a column for percentage of total transactions?

This worked with your sample data.

DECLARE @MinDate DATETIME = '5/8/2017 12:00AM';
DECLARE @MaxDate DATETIME = '5/8/2017 11:59PM';

WITH cam1 AS ( 
    SELECT TransDetailID,AVClassID
    FROM AVTransDetail
    WHERE CreatedDate BETWEEN @MinDate AND @MaxDate
    AND
    CamID = 1),

cam2 AS (
    SELECT TransDetailID,AVClassID
    FROM AVTransDetail
    WHERE CreatedDate BETWEEN @MinDate AND @MaxDate
    AND
    CamID = 2)

SELECT COUNT(*)'Total',SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END)'NonMatch',
       SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END) * 100.00/COUNT(*)'Percentage'
FROM cam1 c1
     JOIN cam2 c2 ON c1.TransDetailID=c2.TransDetailID

Try the below SQL script.

First we LAG to find the differences. Then, we get each transaction and whether there is a difference. And finally, we get the percentage.

DECLARE @MinDate DATE = '2017/04/06',
        @MaxDate DATE = '2017/05/09';

SELECT count(*) AS TotalTransactions
    ,sum(Change) AS TransactionsWithChange
    ,(cast(sum(Change) AS FLOAT) / cast(count(*) AS FLOAT)) AS ChangePercent
FROM (
    SELECT TransDetailID
        ,MAX(classChange) AS Change
    FROM (
        SELECT *
            ,LAG(AVClassID, 1, AVClassID) OVER (
                PARTITION BY TransDetailID ORDER BY AVDetailID
                ) AS PrevClassId
            ,CASE 
                WHEN LAG(AVClassID, 1, AVClassID) OVER (
                        PARTITION BY TransDetailID ORDER BY AVDetailID
                        ) != AVClassID
                    THEN 1
                ELSE 0
                END AS ClassChange
        FROM AVTransDetail
        where CreatedDate between @MinDate and @MaxDate
        ) AS CoreData
    GROUP BY TransDetailID
    ) AS ChangeData

Hope this helps.

I added more sample rows to get better result

create table #trans (
    AVDetailID int,
    TransDetailID int,
    AVClassID int,
    CamID int,
    CreatedDate datetime
)

insert into #trans values 
( 20101522, 54125478, 5, 1, '2017-05-08 10:15:01:560'),
( 20101523, 54125478, 5, 2, '2017-05-08 10:15:01:620'),
( 20101524, 54125479, 3, 1, '2017-05-08 10:15:03:120'),
( 20101525, 54125479, 2, 2, '2017-05-08 10:15:03:860'),
( 20101526, 54125480, 4, 1, '2017-05-08 10:15:06:330'),
( 20101527, 54125480, 4, 2, '2017-05-08 10:15:06:850'),
( 20101528, 54125481, 4, 1, '2017-05-08 10:15:07:850'),
( 20101529, 54125481, 5, 2, '2017-05-08 10:15:09:850'),
( 20101530, 54125482, 4, 1, '2017-05-08 10:15:07:850'),
( 20101531, 54125482, 5, 3, '2017-05-08 10:15:09:850')

;with diff as (
    -- select records that have different class 
    select CamID as Ent_CamID, count(*) diff_Count
    from #trans ent 
        outer apply (
            select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans 
            where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
            order by CamID, CreatedDate desc
        ) ext
    where ent.AVClassID <> ext.x_AVClassID
    group by ent.CamID, ext.x_CamID
    union
    select ext.x_CamID as Ext_CamID, count(*) diff_Count
    from #trans ent 
        outer apply (
            select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans 
            where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
            order by CamID, CreatedDate desc
        ) ext
    where ent.AVClassID <> ext.x_AVClassID
    group by ent.CamID, ext.x_CamID
)
, perc as (
    select Ent_CamID as CamID, sum(diff_Count) Total_Error
    , (select count(*) 
       from #trans where CamID = diff.Ent_CamID 
       group by CamID) AS Total_Capture
    from diff
    group by Ent_CamID
)
select CamID, Total_Error, Total_Capture, 100*(Total_Error)/Total_Capture Error_Percentage
from perc

Result:

CamID   Total_Error Total_Capture   Error_Percentage
1       3           5               60
2       2           4               50
3       1           1               100

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM