简体   繁体   中英

SQL Server : dependent subqueries

I am trying to count difference(deduct) between two TIMEs which are all saved in one table but at different rows and columns as well. I am using SQL Server 2008 R2 Express (version 10.50.2500.0) at NT INTEL X86 Platform.

I have a table just like this one:

CREATE TABLE TBL_DATA 
(
     id INT IDENTITY(1,1) PRIMARY KEY,                   
     opid INT, 
     lotid INT,                    
     dt_date DATE,
     dt_begin_test TIME,
     dt_end_test TIME
);

This table is loaded with data / for example:

id     opid lotid   dt_date     dt_begin_test       dt_end_test
----------------------------------------------------------------------
5800    352 13381   2016-01-27  08:17:18.0000000    08:17:40.0000000
5801    352 13381   2016-01-27  08:17:49.0000000    08:18:11.0000000
5802    352 13381   2016-01-27  08:18:18.0000000    08:18:40.0000000
5803    319 13381   2016-01-27  08:18:11.0000000    08:18:33.0000000
5804    352 13381   2016-01-27  08:18:48.0000000    08:19:10.0000000
5805    352 13381   2016-01-27  08:19:18.0000000    08:19:39.0000000
5806    319 13381   2016-01-27  08:18:59.0000000    08:19:21.0000000
5807    352 13381   2016-01-27  08:19:47.0000000    08:20:09.0000000
5808    352 13381   2016-01-27  08:20:16.0000000    08:20:38.0000000
5809    319 13381   2016-01-27  08:19:59.0000000    08:20:21.0000000
5810    352 13381   2016-01-27  08:20:45.0000000    08:21:07.0000000
5811    352 13381   2016-01-27  08:21:14.0000000    08:21:36.0000000
5812    319 13381   2016-01-27  08:20:50.0000000    08:21:12.0000000
5813    352 13381   2016-01-27  08:21:43.0000000    08:22:05.0000000
5814    319 13381   2016-01-27  08:21:27.0000000    08:21:49.0000000
5815    352 13381   2016-01-27  08:22:12.0000000    08:22:33.0000000
5816    319 13381   2016-01-27  08:22:04.0000000    08:22:26.0000000
5817    352 13381   2016-01-27  08:22:41.0000000    08:23:02.0000000

What I would like to get is output for user with opid=352 , for example, where I need to deduct dt_begin_test value of line 5805 from dt_end_test value of line 5804 , for example. The result should be 8 seconds . And make it for all lines of user with opid=352 .

There is a very pretty solution in case there would be only one opid value in the table TBL_DATA .

 SELECT TBL_TEST.id, 
        TBL_TEST.opid, 
        TBL_TEST.lotid,         
        TBL_TEST.dt_date, 
        TBL_TEST.dt_begin_test, 
        TBL_TEST.dt_end_test,       
        COALESCE(
            DATEDIFF(
                     second, (
                     SELECT TBL_TMP.dt_end_test
                     FROM [TBL_DATA] AS TBL_TMP 
                     WHERE TBL_TMP.id = TBL_TEST.id - 1),                   
                     TBL_TEST.dt_begin_test), 0) AS PAR_DEDUCT
FROM [TBL_DATA] AS TBL_TEST

Unfortunately this solution fails in case that you must deduct values from rows which are not one after one.

I case of:

SELECT TBL_TEST.id, 
        TBL_TEST.opid, 
        TBL_TEST.lotid,         
        TBL_TEST.dt_date, 
        TBL_TEST.dt_begin_test, 
        TBL_TEST.dt_end_test,       
        COALESCE(
            DATEDIFF(
                     second, (
                     SELECT TBL_TMP.dt_end_test
                     FROM [TBL_DATA] AS TBL_TMP 
                     WHERE TBL_TMP.id = TBL_TEST.id - 1),                   
                     TBL_TEST.dt_begin_test), 0) AS PAR_DEDUCT
FROM [TBL_DATA] AS TBL_TEST
WHERE opid=352;

it does not work correctly what I understand.

For that I had an idea that I will use row_number() function to create a new column and then use another select to do it. Slightly modified SELECT query as follows:

SELECT *,
COALESCE(DATEDIFF(second, 
        (SELECT dt_end_test FROM TBL_A AS TBL_TMP WHERE TBL_A.PAR_INDEX = TBL_TMP.PAR_INDEX - 1), 
                TBL_A.dt_begin_test), 0) AS PAR_DEDUCT
FROM
(SELECT row_number() OVER (ORDER BY TBL_TEST.id) AS PAR_INDEX,
    TBL_TEST.id, 
    TBL_TEST.opid, 
    TBL_TEST.lotid, 
    TBL_TEST.dt_date, 
    TBL_TEST.dt_begin_test, 
    TBL_TEST.dt_end_test
FROM [TBL_DATA] AS TBL_TEST
WHERE opid=352
) AS TBL_A;

Unfortunately it does not work. It has a problem with TBL_A parameter in DATEDIFF ... SELECT statement.

I can do it in another way. I could save results in a temporary table and then do it as mentioned above. What I would like is to do it in one execution / command.

Any help is very appreciated.

Tomas.

You might be able to do what you want using Row_number in a cte and left joining it to itself.

;WITH    cte AS (
    SELECT  *,
            ROW_NUMBER() OVER (PARTITION BY opid,lotid ORDER BY dt_date, dt_begin_test) Rn
    FROM    TBL_DATA
)
SELECT  t1.*,
        DATEDIFF(SECOND,t2.dt_end_test,t1.dt_begin_test)
FROM    cte t1
        LEFT JOIN cte t2 ON t1.opid = t2.opid
                            AND t1.lotid = t2.lotid
                            AND t1.Rn - 1 = t2.Rn
ORDER BY t1.opid,
        t1.lotid,
        t1.dt_date,
        t1.dt_begin_test

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