咱們的系統中記錄了用戶的鼠標行爲軌跡字符串,這些字符串的格式是:PosSet:[573,1103,2010-09-03 22:32:35],[864,110,2010-09-03 22:32:57],這個字段表示用戶點擊頁面的X座標,Y座標,時間。如今要求對這樣字符串進行分割。html
須要注意的是當字符串只有一個座標的時候,如:PosSet:[513,1303,2010-09-03 22:34:35],你須要考慮這種狀況的處理,由於這個時候就沒有分隔字符在字符串了。數據庫
還須要考慮字符串不規則的時候的異常處理;函數
(Figure1:基礎數據)性能
(Figure2:實現效果圖)測試
在正式解決問題以前我先提供一個遊標的模板,它簡單的實現了找出數據庫中全部的數據庫名,其實這個模板的目的是爲了提供一個規範化的遊標SQL代碼模板。spa
--遊標模板 DECLARE @databaseName VARCHAR(100) DECLARE @itemCur CURSOR SET @itemCur = CURSOR FOR SELECT name FROM sys.databases WHERE database_id > 4 OPEN @itemCur FETCH NEXT FROM @itemCur INTO @databaseName WHILE @@FETCH_STATUS=0 BEGIN --邏輯處理 PRINT @databaseName FETCH NEXT FROM @itemCur INTO @databaseName END CLOSE @itemCur DEALLOCATE @itemCur
(Figure3:返回數據庫名)code
(一) 首先建立測試表VisiteLog,並插入測試數據:htm
--建立測試表[VisiteLog] CREATE TABLE [dbo].[VisiteLog]( [Id] [int] IDENTITY(1,1) NOT NULL, [PosSet] [varchar](500) NULL, CONSTRAINT [PK_VisiteLog] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO --插入測試數據 SET IDENTITY_INSERT [dbo].[VisiteLog] ON INSERT [dbo].[VisiteLog] ([Id], [PosSet]) VALUES (1, N'[573,1103,2010-09-03 22:32:35],[864,110,2010-09-03 22:32:57]') INSERT [dbo].[VisiteLog] ([Id], [PosSet]) VALUES (2, N'[513,1303,2010-09-03 22:34:35]') SET IDENTITY_INSERT [dbo].[VisiteLog] OFF --查看數據 SELECT * FROM [dbo].[VisiteLog]
(Figure4:基礎數據)blog
(二) 接着建立表PosSetInfo,這個表是用來保存鼠標軌跡字符串分割後的數據:ip
--建立表[PosSetInfo] CREATE TABLE [dbo].[PosSetInfo]( [ID] [int] NULL, [PosSet_x] [int] NULL, [PosSet_y] [int] NULL, [PosTime] [datetime] NULL ) ON [PRIMARY] GO
(三) 根據鼠標軌跡字符串:[573,1103,2010-09-03 22:32:35],[864,110,2010-09-03 22:32:57]。它座標點與座標點之間的分隔符是「,」,X座標與Y座標一樣適用分隔符「,」,這給咱們的分割帶來了一些不便,因此咱們建立了一個函數,它的做用是把字符串@str以@split分隔符進行分隔,返回第@index次匹配的元素。以下圖所示:
-- ============================================= -- Author: <聽風吹雨> -- Create date: <2010/05/27> -- Description: <把字符串@str以@split分隔符進行分隔,返回第@index次匹配的元素> -- ============================================= CREATE FUNCTION [dbo].[Get_StrArrayStrOfIndex] ( @str VARCHAR(5000), --要分割的字符串 @split VARCHAR(10), --分隔符號 @index INT --取第幾個元素 ) RETURNS VARCHAR(5000) AS BEGIN DECLARE @location INT DECLARE @start INT DECLARE @next INT DECLARE @seed INT SET @str=LTRIM(RTRIM(@str)) SET @start=1 SET @next=1 SET @seed=LEN(@split) SET @location=CHARINDEX(@split,@str) WHILE @location<>0 and @index>@next BEGIN SET @start=@location+@seed SET @location=CHARINDEX(@split,@str,@start) SET @next=@next+1 END IF @location =0 SELECT @location =LEN(@str)+1 RETURN SUBSTRING(@str,@start,@location-@start) END --測試函數 SELECT DBO.[Get_StrArrayStrOfIndex]('AB,CDE,FG,HIJK',',',3);
(Figure5:函數測試效果)
(四) 下面的SQL腳本就是對VisiteLog表的數據進行分割,再把分割後的字符串保存到PosSetInfo表中,這個腳本的主要作法是先把[573,1103,2010-09-03 22:32:35],[864,110,2010-09-03 22:32:57]以「]」作爲分隔符,把數據分割成兩段:[573,1103,2010-09-03 22:32:35]和[864,110,2010-09-03 22:32:57],再以「,」作爲分割符,找出X座標、Y座標和時間;
--鼠標軌跡字符串分割 DECLARE @ID int,@PosSet VARCHAR(2000) DECLARE @splitlen INT DECLARE @split NVARCHAR(10) DECLARE @temp VARCHAR(100) DECLARE @PosSet_x INT DECLARE @PosSet_y INT DECLARE @PosTime DATETIME SET @split = ']' DECLARE @itemCur CURSOR SET @itemCur = CURSOR FOR SELECT ID,PosSet FROM [VisiteLog] WHERE PosSet <> '' OPEN @itemCur FETCH NEXT FROM @itemCur INTO @ID,@PosSet WHILE @@FETCH_STATUS=0 BEGIN SET @splitlen=LEN(@split+'a')-2 WHILE CHARINDEX(@split,@PosSet)>0 BEGIN SET @Temp = LEFT(@PosSet,CHARINDEX(@split,@PosSet)-1) SET @Temp = replace(replace(@Temp,',[',''),'[','') SET @PosSet_x = dbo.Get_StrArrayStrOfIndex(@Temp,',',1) SET @PosSet_y = dbo.Get_StrArrayStrOfIndex(@Temp,',',2) SET @PosTime = dbo.Get_StrArrayStrOfIndex(@Temp,',',3) INSERT PosSetInfo VALUES(@ID,@PosSet_x,@PosSet_y,@PosTime) SET @PosSet=STUFF(@PosSet,1,CHARINDEX(@split,@PosSet)+@splitlen,'') END FETCH NEXT FROM @itemCur INTO @ID,@PosSet END CLOSE @itemCur DEALLOCATE @itemCur
執行完上面運用遊標的SQL腳本,如今查看PosSetInfo表的數據,返回的結果以下圖所示:
--查看數據 SELECT * FROM [dbo].[PosSetInfo]
(Figure6:分割後數據)
(一) 若是須要循環每一個數據庫進行操做,你可使用下面的SQL腳本:
--循環每一個數據庫 EXEC sp_MSForEachDB 'USE [?]; SELECT * FROM sys.database_files'
(Figure7:sp_MSForEachDB效果圖)
更多sp_MSForEachDB和sp_MSforeachtable的運用,能夠參考:
SQL Server 遊標運用:查看一個數據庫全部表大小信息(Sizes of All Tables in a Database)
SQL Server 遊標運用:查看全部數據庫全部表大小信息(Sizes of All Tables in All Database)
(二) 步驟四中處理SQL代碼可能性能不是最優的,由於就函數Get_StrArrayStrOfIndex的調用就已經很是頻繁的,若是一個PosSet字段的值很是多,你能夠考慮用一個表值函數返回一個表。