The Problem

当我们处理存档数据或内存数据时,我们想要自定义命名表名,数据库,架构加上日期,时间,或者应用名时,用标准的TSQL来实现是比较困难的。

假设我们有一张日志表,增长速度异常快。但是你不需要超过一个星期的数据,应该怎么做呢?

表分区当然是最佳选择了,但只有企业版里面有这项功能,难道我们就没有其他选择了吗?当然是有的,先来准备点数据吧。

准备数据:

USE AdventureWorks2014;
GO
IF OBJECT_ID('dbo.Database_Log') IS NOT NULL
BEGIN
DROP TABLE dbo.Database_Log
END CREATE TABLE dbo.Database_Log
(
log_id INT NOT NULL
IDENTITY(1, 1)
CONSTRAINT PK_Database_Log PRIMARY KEY CLUSTERED ,
Log_Time DATETIME ,
Log_Data NVARCHAR(1000)
); DECLARE @datetime DATETIME = CURRENT_TIMESTAMP;
DECLARE @datediff TABLE
(
previous_hour SMALLINT
); DECLARE @count SMALLINT = 0;
WHILE @count <= 360
BEGIN
INSERT INTO @datediff
( previous_hour )
SELECT @count;
SELECT @count = @count + 1
END
SELECT @count = 0;
WHILE @count <= 1000
BEGIN
INSERT INTO Database_Log
( Log_Time ,
Log_Data
)
SELECT DATEADD(HOUR, -1 * previous_hour, CURRENT_TIMESTAMP) ,
CAST(DATEADD(HOUR, -1 * previous_hour,
CURRENT_TIMESTAMP) AS NVARCHAR)
FROM @datediff;
SELECT @count = @count + 1;
END
DECLARE @year_offset TINYINT = 5;
WHILE @year_offset > 0
BEGIN
INSERT INTO dbo.Database_Log
( Log_Time ,
Log_Data
)
SELECT TOP 10000
DATEADD(YEAR, -1 * @year_offset, Log_Time) ,
CAST(DATEADD(YEAR, -1 * @year_offset, Log_Time) AS NVARCHAR)
FROM Database_Log
SELECT @year_offset = @year_offset - 1;
END

The Solution

假设我们存档数据格式是,每年为数据库,每星期为一个表。如:dbo.database_log_2016为数据库,其中 dbo.database_log_2016_32为表。

我们动态SQL应该如何实现呢? 先整理一下思路

  • 获取日志记录通过时间段
  • 创建数据库或表(如果他们不存在)
  • 进行插入操作
  • 删除原始数据

代码:

DECLARE @sql_command NVARCHAR(MAX);
DECLARE @parameter_list NVARCHAR(MAX) = '@start_of_week DATETIME, @end_of_week DATETIME';
DECLARE @min_datetime DATETIME; SELECT @min_datetime = MIN(Log_Time)
FROM Database_Log; DECLARE @previous_min_time DATETIME = '1/1/1900';
DECLARE @start_of_week DATETIME = CAST(DATEADD(dd, -1 * (DATEPART(dw, @min_datetime) - 1), @min_datetime) AS DATE);
DECLARE @end_of_week DATETIME = DATEADD(WEEK, 1, @start_of_week);
DECLARE @current_year SMALLINT;
DECLARE @current_week TINYINT;
DECLARE @database_name NVARCHAR(128);
DECLARE @table_name NVARCHAR(128); WHILE (@previous_min_time <> @min_datetime)
BEGIN
SELECT @current_year = DATEPART(YEAR, @start_of_week);
SELECT @current_week = DATEPART(WEEK, @start_of_week);
SELECT @database_name = 'Database_Log_' + CAST(@current_year AS NVARCHAR); -- Create the yearly database if it does not already exist
SELECT @table_name = 'Database_Log_' + CAST(@current_year AS NVARCHAR) + '_' + CAST(@current_week AS NVARCHAR)
IF NOT EXISTS(SELECT *FROM sys.databases WHERE databases.name = @database_name)
BEGIN
SELECT @sql_command = 'CREATE DATABASE [' + @database_name + ']';
EXEC sp_executesql @sql_command; END -- Create the weekly table if it does not already exist
SELECT @sql_command = '
USE [' + @database_name + '];
IF NOT EXISTS (SELECT * FROM sys.tables WHERE tables.name = ''' + @table_name + ''')
BEGIN
CREATE TABLE [dbo].[' + @table_name + ']
(Log_Id INT NOT NULL CONSTRAINT PK_Database_Log_' + CAST(@current_year AS NVARCHAR) + '_' + CAST(@current_week AS NVARCHAR) + ' PRIMARY KEY CLUSTERED,
Log_Time DATETIME,
Log_Data NVARCHAR(1000));
END' EXEC sp_executesql @sql_command; SELECT @sql_command = '
INSERT INTO [' + @database_name + '].[dbo].[' + @table_name + ']
(Log_Id, Log_Time, Log_Data) SELECT
Log_Id,
Log_Time,
Log_Data
FROM AdventureWorks2014.dbo.Database_Log
WHERE
Log_Time >= @start_of_week
AND Log_Time <= @end_of_week
AND Log_Time < DATEADD(WEEK, -1, CURRENT_TIMESTAMP); DELETE
FROM AdventureWorks2014.dbo.Database_Log
WHERE
Log_Time >= @start_of_week
AND Log_Time <= @end_of_week
AND Log_Time < DATEADD(WEEK, -1, CURRENT_TIMESTAMP);' EXEC sp_executesql @sql_command,@parameter_list,@start_of_week,@end_of_week SELECT @previous_min_time = @min_datetime; SELECT @min_datetime = MIN(Log_Time)
FROM Database_Log; SELECT @start_of_week = CAST(DATEADD(dd, -1 * (DATEPART(dw, @min_datetime) - 1), @min_datetime) AS DATE); SELECT @end_of_week = DATEADD(WEEK, 1, @start_of_week); END

结语

善使用动态TSQL会让你在工作中的心情变得更美好,当然也可能更恶劣。以后还会讲到如何使用动态TSQL来备份数据库,索引管理。

T-SQL Recipes之Organizing and Archiving Data的更多相关文章

  1. SQL2008安装时,“provider: 命名管道提供程序, error: 40 - 无法打开到 SQL Server 的连接) (.Net SqlClient Data Provider)” 错误的解决方案

    错误提示: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接. (provide ...

  2. SQL Fundamentals:Restricting and Sorting Data限制和排序数据(FROM-WHERE-SELECT-ORDER BY)

    SQL Fundamentals || Oracle SQL语言 控制操作的显示列:基本的SELECT语句 控制行:限定查询和排序显示 分组统计查询 限定查询:WHERE字句 排序显示:ORDER B ...

  3. SQL Server2008 错误源:.net SqlClient data provider的解决方法

    今天下午直接在SQL Server 2008的Microsoft SQL Server Management Studio 中修改一张表中某个字段, 不管是删除字符还是添加都提示下面的错误. 网上很多 ...

  4. 20180820 SQL 提示Error: String or binary data would be truncated

    Error: String or binary data would be truncated,错误,是因为栏位给出的长度不够,增加初始化长度就可以了. 除了创建表的增加长度情况,还有一种是,SELE ...

  5. 未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接) (.Net SqlClient Data Provider)

    今天连接服务器的SQL Server 遇到了一个很经典的问题 之前也曾多次遇到过 这次记录一下 按照之前经验 首先 开启了服务中的 SQL Server(MSSQLSERVER)和ASP.NET St ...

  6. Spark SQL External Data Sources JDBC简易实现

    在spark1.2版本中最令我期待的功能是External Data Sources,通过该API可以直接将External Data Sources注册成一个临时表,该表可以和已经存在的表等通过sq ...

  7. 转载:Character data is represented incorrectly when the code page of the client computer differs from the code page of the database in SQL Server 2005

    https://support.microsoft.com/en-us/kb/904803 Character data is represented incorrectly when the cod ...

  8. sql是如何执行一个查询的!

    引用自:http://rusanu.com/2013/08/01/understanding-how-sql-server-executes-a-query/ Understanding how SQ ...

  9. [Windows Azure] Data Management and Business Analytics

    http://www.windowsazure.com/en-us/develop/net/fundamentals/cloud-storage/ Managing and analyzing dat ...

随机推荐

  1. mysql SQL优化之嵌套查询-遁地龙卷风

    (-1) 写在前面 这篇随笔的数据使用的是http://blog.csdn.net/friendan/article/details/8072668#comments里的,里面有一些常见的select ...

  2. C# 3种方法连接MySql

    转   http://wenku.baidu.com/view/d0cf34708e9951e79b8927c7.html C# 连接MYSQL数据库的方法及示例 连接MYSQL数据库的方法及示例 方 ...

  3. JavaScript的模块化之AMD&CMD规范

    前端开发常常会遇到的问题: 1.恼人的命名冲突: 2.繁琐的文件依赖: 模块化开发的优势: 1.解决命名冲突和依赖管理: 2.模块的版本管理: 3.提高代码的可维护性: 4.前端性能优化: JavaS ...

  4. Vue.js:轻量高效的前端组件化方案

    转发一篇尤老师对vue.js的介绍,了解vue.js的来龙去脉.不过现在已经是2.0了,也有添加一些新的东西,当然有些东西也改了. Vue.js:轻量高效的前端组件化方案 Vue.js 是我在2014 ...

  5. python拆分CANLog

    通过CANOE 导出的log通常有很多个ID的数据,如何才能找到某一个ID下的特殊的信号?利用python可以简单的进行这个步骤,代码如下: 说明: 最终的效果是将log信息,分不同的ID进行拆分,并 ...

  6. php检测文件内容编码的方法

    核心用到的是mb_convert_encoding函数,示例代码如下: <?php header("Content-type: text/html; charset=utf-8&quo ...

  7. 手写一个allocator

    似乎就像是一个计算机原理的实践.. 首先介绍一下大多数操作系统的内存架构..对于某个程序它会认为自己是独占了整个系统的所有内存在运行的这样才能方便移植,因此人们搞出了虚拟内存和物理内存的区别,于是人们 ...

  8. Android UI自动化用例设计技巧

    一.封装方法 1.编程如何越来越快: 首先,需要经验丰富,知识面广. 其次,每一个熟练编程的人员,都会有自己的一个库,解决各种问题.各种通用的方法函数. 同理,自动化脚本也是编程,测试用例则为需求,U ...

  9. Transaction (Process ID xxx) was deadlocked on lock

    Transaction (Process ID 161) was deadlocked on lock | communication buffer resources with another pr ...

  10. C++开始前篇,深入编译链接(补充2)

    在开始链接之前,我们先了解几个概念: 一>符号的概念. 我们知道,链接的最重要的是"对符号的重定位",而且上面提到了符号表,那什么是符号呢,在链接中,我们将函数和变量统称为符 ...