2016-04-28 433 views
1

我正在尋找聚合日誌中數據的最佳方法。下表是「誰在車站上」的日誌。例如日誌表聚合

用戶1是在STATION1「2014年10月2日14點46分」和「2014年10月2日14點五十零」之間(2個交易)

用戶2是在STATION1 10/2之間」/2014 15:00" 和 「2014年10月2日15:15」(5個交易)

用戶3是對在STATION1 2014年10月3日16點31(1交易)

用戶2再次在2014年10月2日17:04和2014年10月2日17:06之間的station1上的同一天

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

我正在尋找像輸出「是站上多長時間的用戶,有多少交易」 ...是有可能做同樣的相同,而無需通過每個項目迭代?如果是這樣,我該怎麼辦呢?

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

我的SQL Server 2012年 – user173552

+0

爲什麼有多個行的STATION1 \t 2014年10月2日15:00 \t User2? – FLICKER

+0

我的要求是獲取用戶每次訪問該站的詳細信息......(在給定時間內,只有一個用戶可以在該站上)。 – user173552

回答

0

運行這些腳本

腳本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 

腳本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 

腳本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 

等待1或2天的用戶的交易,並將它們運行

DECLARE @return_value int 

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

SELECT 'Return Value' = @return_value 

GO 
+0

感謝您回答這個問題,但是,您不應該引用個人共享文件夾..而是將您的所有腳本寫入您的答案正文中。 – FLICKER

+0

你應該編輯你的問題,並提供所有腳本在一個單一的職位。我認爲你已經在單獨的帖子中發佈了每個腳本。此外,只要你想改變你的答案,請編輯你的問題,不要發佈新的答案,即使你提供了多個解決方案,所有應該在一個職位。 – FLICKER

0

設置數據:

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') 

查詢:

;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 

結果:

+----------+----------+-------------------------+----------+------------------+ 
| 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 | 
+----------+----------+-------------------------+----------+------------------+ 

請「標記爲答案」,如果一個帖子已經回答了這個問題