2016-04-28 4 views
1

Ich bin auf der Suche nach dem besten Ansatz zum Aggregieren von Daten in einem Protokoll. In der Tabelle unten ist ein Protokoll von "wer war auf einer Station". ZBLog-Tabelle Aggregation

User1 war auf dem station1 zwischen "2014.10.02 14.46" und "2014.10.02 14.50" (2 Transaktionen)

User2 war auf dem station1 zwischen „10/2/2014 15:00" und "2014.10.02 15.15" (5 Transaktionen)

user3 auf der station1 bei 2014.10.03 16.31 (1-Transaktion)

User2 war, war wieder am selben Tag auf der Station1 zwischen "02.10.2014 17:04" und "02.10.2014 17:06" (2 Transaktionen)

Station1 \t 10/2/2014 14:46 \t User1 
 
Station1 \t 10/2/2014 14:50 \t User1 
 
Station1 \t 10/2/2014 15:00 \t User2 
 
Station1 \t 10/2/2014 15:00 \t User2 
 
Station1 \t 10/2/2014 15:00 \t User2 
 
Station1 \t 10/2/2014 15:00 \t User2 
 
Station1 \t 10/2/2014 15:15 \t User2 
 
Station1 \t 10/2/2014 16:31 \t User3 
 
Station1 \t 10/2/2014 17:04 \t User2 
 
Station1 \t 10/2/2014 17:06 \t User2

Ich bin für eine Ausgabe wie „Wie lange der Benutzer war auf der Station und wie viele Transaktionen“ ... Ist es möglich, ohne den Umweg über jedes Element iteriert same same zu tun? Wenn ja, wie gehe ich vor?

station  User start time  Duration Transactions 
 
Station1 \t User1 \t 10/2/2014 14:46 \t 4 min  2 
 
Station1 \t User2 \t 10/2/2014 15:00 \t 15 min  5 
 
Station1 \t User3 \t 10/2/2014 16:31 \t    1 
 
Station1 \t User2 \t 10/2/2014 15:04 2 min  2

+0

Ich bin auf SQL Server 2012. – user173552

+0

, warum gibt es mehrere Zeilen für Station1 \t 2014.10.02 beantwortet hat 15:00 \t Benutzer2? – FLICKER

+0

Meine Anforderung besteht darin, Details zu jedem Besuch eines Benutzers an die Station zu senden ... (nur ein Benutzer kann in einer bestimmten Zeit an der Station sein). – user173552

Antwort

0

Führen Sie diese Skripts

Script 1

-- ============================================= 
-- Author:  Carlos Aguilar 
-- Create date: April 2016 
-- Description: Massive Creation of Log Tables in a Database 
-- ============================================= 

DECLARE @SCRIPT NVARCHAR(MAX) 
DECLARE @TABLE NVARCHAR(MAX) 
DECLARE @COLUMNS NVARCHAR(MAX) 

DECLARE _LOGS_ CURSOR FOR 
    SELECT NAME FROM SYSOBJECTS WHERE TYPE = 'U' AND NAME NOT LIKE '__LOG_%' 

OPEN _LOGS_ 



BEGIN TRY 

    BEGIN TRAN 

    FETCH NEXT FROM _LOGS_ INTO @TABLE 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 

    SET @COLUMNS = '' 

    SELECT @COLUMNS = @COLUMNS + '[' + T1.NAME + '] ' + T2.NAME + 
     CASE 
      WHEN T1.XTYPE IN (106, 108) THEN 
       '(' + CONVERT(VARCHAR, T1.XPREC) + ', ' + CONVERT(VARCHAR, T1.XSCALE) + ')'  
      WHEN T1.XTYPE IN (173, 175, 42, 43, 239, 231, 41, 165, 167) THEN 
       '(' + CASE WHEN T1.LENGTH = -1 THEN 'MAX' ELSE CONVERT(VARCHAR, T1.LENGTH) END + ')' 
      ELSE 
       '' 
     END 
     + ' NULL, ' 
    FROM SYSOBJECTS T0 
     INNER JOIN SYSCOLUMNS T1 
      ON T0.ID = T1.ID 
     INNER JOIN sys.TYPES T2 
      ON T1.XTYPE = T2.SYSTEM_TYPE_ID 
    WHERE T0.TYPE = 'U' AND 
     T0.NAME NOT LIKE '__LOG_%' AND 
     T0.NAME = @TABLE AND 
     T1.XTYPE NOT IN (34, 35, 99) AND 
     T2.NAME <> 'sysname' 

    SELECT @SCRIPT = 
    'CREATE TABLE __LOG_' + @TABLE + '(' + @COLUMNS + ' 
     [__DB_USER] nvarchar(128) NULL, 
     [__APP_NAME] nvarchar(128) NULL, 
     [__HOST_NAME] nvarchar(128) NULL, 
     [__IP_ADD] sql_variant NULL, 
     [__EVENT] varchar(1) NULL, 
     [__TIME] datetime NULL, 
     [__PROTOCOL] sql_variant NULL) ' 

    PRINT @SCRIPT 

    EXEC (@SCRIPT) 

    SELECT @SCRIPT = 'DELETE FROM __LOG_' + @TABLE 

    PRINT @SCRIPT 

    EXEC (@SCRIPT) 

    FETCH NEXT FROM _LOGS_ INTO @TABLE 

    END 

    COMMIT 

END TRY 
BEGIN CATCH 

    ROLLBACK 
    PRINT 'ERROR: ' + ERROR_MESSAGE() 

END CATCH 

CLOSE _LOGS_ 
DEALLOCATE _LOGS_ 

GO 

Script 2

-- ============================================= 
-- Author:  Carlos Aguilar 
-- Create date: April 2016 
-- Description: Massive Creation of Trigger for Log Tables in a Database 
-- ============================================= 

DECLARE @COLUMNS NVARCHAR(MAX) 
DECLARE @SCRIPT NVARCHAR(MAX) 
DECLARE @TABLE NVARCHAR(MAX) 

DECLARE _LOGS_ CURSOR FOR 
    SELECT NAME FROM SYSOBJECTS WHERE TYPE = 'U' AND NAME NOT LIKE '__LOG_%' 

OPEN _LOGS_ 



BEGIN TRY 

    BEGIN TRAN 

    FETCH NEXT FROM _LOGS_ INTO @TABLE 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 

    SET @COLUMNS = '' 

    SELECT @COLUMNS = @COLUMNS + '[' + T1.NAME + '], ' 
    FROM SYSOBJECTS T0 
     INNER JOIN SYSCOLUMNS T1 
      ON T0.ID = T1.ID 
    WHERE T0.TYPE = 'U' AND 
     T0.NAME NOT LIKE '__LOG_%' AND 
     T0.NAME = @TABLE AND 
     T1.XTYPE NOT IN (34, 35, 99) 

    SELECT @SCRIPT = 'CREATE TRIGGER [dbo].[__LOG_INSERT_' + @TABLE + '] ON [dbo].[' + @TABLE + '] 
       WITH ENCRYPTION, EXECUTE AS CALLER 
       FOR INSERT 
       AS 
       BEGIN 
        INSERT INTO __LOG_' + @TABLE + '(' + 
        @COLUMNS + ' 
        __DB_USER, 
        __APP_NAME, 
        __HOST_NAME, 
        __IP_ADD, 
        __EVENT, 
        __TIME, 
        __PROTOCOL) 
        SELECT ' + @COLUMNS + ' 
         SUSER_SNAME() AS __DB_USER , 
         APP_NAME () AS __APP_NAME, 
         HOST_NAME() AS __HOST_NAME, 
         CONNECTIONPROPERTY(''client_net_address'') __IP_ADD, 
         ''I'' AS __EVENT, 
         GETDATE() AS __TIME, 
         CONNECTIONPROPERTY(''protocol_type'') AS __PROTOCOL 
        FROM INSERTED 

       END' 

     PRINT @SCRIPT 

     EXEC (@SCRIPT) 

     SELECT @SCRIPT = 'CREATE TRIGGER [dbo].[__LOG_UPDATE_' + @TABLE + '] ON [dbo].[' + @TABLE + '] 
       WITH ENCRYPTION, EXECUTE AS CALLER 
       FOR UPDATE 
       AS 
       BEGIN 
        INSERT INTO __LOG_' + @TABLE + '(' + 
        @COLUMNS + ' 
        __DB_USER, 
        __APP_NAME, 
        __HOST_NAME, 
        __IP_ADD, 
        __EVENT, 
        __TIME, 
        __PROTOCOL) 
        SELECT ' + @COLUMNS + ' 
         SUSER_SNAME() AS __DB_USER , 
         APP_NAME () AS __APP_NAME, 
         HOST_NAME() AS __HOST_NAME, 
         CONNECTIONPROPERTY(''client_net_address'') __IP_ADD, 
         ''U'' AS __EVENT, 
         GETDATE() AS __TIME, 
         CONNECTIONPROPERTY(''protocol_type'') AS __PROTOCOL 
        FROM INSERTED 

       END' 

     PRINT @SCRIPT 

     EXEC (@SCRIPT) 

     SELECT @SCRIPT = 'CREATE TRIGGER [dbo].[__LOG_DELETE_' + @TABLE + '] ON [dbo].[' + @TABLE + '] 
       WITH ENCRYPTION, EXECUTE AS CALLER 
       FOR DELETE 
       AS 
       BEGIN 
        INSERT INTO __LOG_' + @TABLE + '(' + 
        @COLUMNS + ' 
        __DB_USER, 
        __APP_NAME, 
        __HOST_NAME, 
        __IP_ADD, 
        __EVENT, 
        __TIME, 
        __PROTOCOL) 
        SELECT ' + @COLUMNS + ' 
         SUSER_SNAME() AS __DB_USER , 
         APP_NAME () AS __APP_NAME, 
         HOST_NAME() AS __HOST_NAME, 
         CONNECTIONPROPERTY(''client_net_address'') __IP_ADD, 
         ''D'' AS __EVENT, 
         GETDATE() AS __TIME, 
         CONNECTIONPROPERTY(''protocol_type'') AS __PROTOCOL 
        FROM DELETED 

       END' 

     PRINT @SCRIPT 

     EXEC (@SCRIPT) 

    FETCH NEXT FROM _LOGS_ INTO @TABLE 

    END 

    COMMIT 

END TRY 
BEGIN CATCH 

    ROLLBACK 
    PRINT 'ERROR: ' + ERROR_MESSAGE() 

END CATCH 

CLOSE _LOGS_ 
DEALLOCATE _LOGS_ 

GO 

Script 3

-- ============================================= 
-- Author:  Carlos Aguilar 
-- Create date: April 2016 
-- ============================================= 

CREATE PROCEDURE dbo.SelectLogByDate 
(
    @StartDate DATETIME, 
    @EndDate DATETIME 
) 
AS 
BEGIN 

    CREATE TABLE #TRANSACTIONS 
    (
     [TIMESTAMP] DATETIME, 
     STATION NVARCHAR(128), 
     [USER] NVARCHAR(128) 
    ) 

    DECLARE @TABLE NVARCHAR(MAX) 
    DECLARE @SQL NVARCHAR(MAX) 
    DECLARE @ParmDefinition NVARCHAR(MAX); 

    SET @ParmDefinition = N'@StartDate DATETIME, @EndDate DATETIME' 

    DECLARE _LOGS_ CURSOR FOR 
    SELECT NAME FROM SYSOBJECTS WHERE TYPE = 'U' AND NAME LIKE '__LOG_%' 

    OPEN _LOGS_ 

    BEGIN TRY 

     BEGIN TRAN 

      FETCH NEXT FROM _LOGS_ INTO @TABLE 

      WHILE (@@FETCH_STATUS = 0) 
      BEGIN 

       SELECT @SQL = 'INSERT INTO #TRANSACTIONS ([TIMESTAMP], STATION, [USER]) SELECT __TIME, __HOST_NAME, __DB_USER FROM ' + 
        @TABLE + ' ' + 
        'WHERE __TIME BETWEEN @StartDate AND @EndDate' 

       EXECUTE sp_executesql @SQL, @ParmDefinition, 
         @StartDate = @StartDate, 
         @EndDate = @EndDate 

       FETCH NEXT FROM _LOGS_ INTO @TABLE 
      END 
     COMMIT 

    END TRY 
    BEGIN CATCH 

    END CATCH 
    CLOSE _LOGS_ 
    DEALLOCATE _LOGS_ 

    SELECT STATION, 
      [USER], 
      MIN([TIMESTAMP]) AS "START TIME", 
      MAX([TIMESTAMP]) AS "END TIME", 
      DATEDIFF(MINUTE, MIN([TIMESTAMP]), MAX([TIMESTAMP])) AS DURATION, 
      COUNT(*) AS TRANSACTIONS 
    FROM #TRANSACTIONS 
    GROUP BY STATION, 
      [USER] 

END 
GO 

Warten 1 oder 2 Tage für Benutzertransaktionen und sie

DECLARE @return_value int 

EXEC @return_value = [dbo].[SelectLogByDate] 
     @StartDate = ?, --Param here 
     @EndDate = ? --Param here 

SELECT 'Return Value' = @return_value 

GO 
+0

Vielen Dank für die Beantwortung der Frage, aber Sie sollten nicht auf einen persönlichen Freigabeordner beziehen .. Schreiben Sie alle Ihre Skripte in den Körper Ihrer Antwort statt. – FLICKER

+0

sollten Sie Ihre Frage bearbeiten und alle Ihre Skripte in einem einzigen Beitrag bereitstellen. Ich denke, Sie haben jedes Skript in einem separaten Post veröffentlicht. Auch wenn Sie Ihre Antwort ändern möchten, bitte EDIT Ihre Frage, nicht eine neue Antwort, auch Ihre bieten mehr als eine Lösung, alle sollten in einem Beitrag sein. – FLICKER

0

Setup-Daten ausführen:

create table #log (Station varchar(20), Dt datetime, UserName varchar(10)) 

insert into #log values 
('Station1', '10/2/2014 14:46', 'User1'), 
('Station1', '10/2/2014 14:50', 'User1'), 
('Station1', '10/2/2014 15:00', 'User2'), 
('Station1', '10/2/2014 15:00', 'User2'), 
('Station1', '10/2/2014 15:00', 'User2'), 
('Station1', '10/2/2014 15:00', 'User2'), 
('Station1', '10/2/2014 15:15', 'User2'), 
('Station1', '10/2/2014 16:31', 'User3'), 
('Station1', '10/2/2014 17:04', 'User2'), 
('Station1', '10/2/2014 17:06', 'User2') 

Abfrage:

;with TranCount as (
select Station, UserName, count(*) Cnt, MIN(Dt) MinDt 
from (select t.*, 
      (row_number() over (partition by Station order by Dt) - 
       row_number() over (partition by UserName order by Dt) 
      ) as grp 
     from #log t 
    ) t 
group by grp, Station, UserName 
) 
-- find time from next record. 
-- also number the records to find IN and OUT entries 
, cte1 as ( 
     select Station, UserName, Dt 
     , LEAD(Dt) over (partition by Station, UserName order by Station, Dt) NextDt 
     , ROW_NUMBER() over (partition by Station, UserName order by Station, Dt) as RN 
     from #log 
     group by Station, UserName, Dt 
) 
-- only select IN entries, the exit time will be in NextDt field. 
-- so ignore the even rows. 
, cte2 as ( 
     select * 
     from cte1 
     where RN % 2 = 1 
) 
select cte2.Station, cte2.UserName, Dt StartTime 
    , DATEDIFF(SECOND, Dt, NextDt)/60 AS Duration, TranCount.Cnt AS TransactionCount 
from cte2 
    inner join TranCount on TranCount.Station = cte2.Station 
     and TranCount.UserName = cte2.UserName 
     and TranCount.MinDt = cte2.Dt 
order by Station, Dt, UserName 

Ergebnis:

+----------+----------+-------------------------+----------+------------------+ 
| Station | UserName |  StartTime  | Duration | TransactionCount | 
+----------+----------+-------------------------+----------+------------------+ 
| Station1 | User1 | 2014-10-02 14:46:00.000 | 4  |    2 | 
| Station1 | User2 | 2014-10-02 15:00:00.000 | 15  |    5 | 
| Station1 | User3 | 2014-10-02 16:31:00.000 | NULL  |    1 | 
| Station1 | User2 | 2014-10-02 17:04:00.000 | 2  |    2 | 
+----------+----------+-------------------------+----------+------------------+ 

Bitte "Mark als Antwort", wenn ein Beitrag die Frage