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. python 2.7 学习笔记--文件的基本操作

    1.打开文件的方式 file_obj = file("文件路径","模式") file_obj = open("文件路径","模式 ...

  2. Linux安装ftp组件过程

    1   安装vsftpd组件 安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件. [root@bogon ~]# yum -y install vsftpd 2 ...

  3. 收藏的Android学习资源

    1. Android中混合开发系列 Android中Java与JavaScript的交互,可用来实现网页与本地APP的交互,信息的传递等: 谈谈App的混合开发,可以让一部分功能由html5开发,这部 ...

  4. 完整mybatis应用

    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-/ ...

  5. 遍历list、set、map和array

    public static void main(String[] args) { /*1. List*/ ArrayList<Integer> list = new ArrayList&l ...

  6. 解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题。 (默认mysql连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池。系统发布第二天访问链接关闭问题。

    解决Mysql连接池被关闭  ,hibernate尝试连接不能连接的问题. (默认MySQL连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池. 所以系统发布第二天访问会 ...

  7. RBAC基于角色的访问控制

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...

  8. 查看sqlserver被锁的表以及如何解锁

    select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran ...

  9. ios语音识别

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #000000; min-height: 15.0px } p.p ...

  10. ios 弹出不同的键盘

    iOS 提供了10种键盘类型,在开发中,我们可以根据不同的需求,选择不同的键盘样式,例如,当我们只需要输入手机号码时,可以选择纯数字类型的键盘(NumbersAndPunctuation),当我们需要 ...