您的位置:首页 > 其它

今拾到了个联合查询, 琢磨了好几个小时, 标记一下

2012-05-25 21:05 351 查看
需求是这样的:

同一台机器上的3个不同数据库之间进行联合查询, 将查询的结果导入一张临时表, 并查询临时表返回统计信息. 用户更具统计信息, 在倒临时表中的实际数据导出文本到txt.

View Code

--动态sql语句基本语法
1 : 普通SQL语句可以用Exec执行
eg:
Select * from tableName
Exec('select * from tableName')
Exec sp_executesql N'select * from tableName' -- 请注意字符串前一定要加N

2:字段名,表名,数据库名之类作为变量时,必须用动态SQL
eg:
declare @fname varchar(20)
set @fname = 'FiledName'
Select @fname from tableName -- 错误,不会提示错误,但结果为固定值FiledName,并非所要。
Exec('select ' + @fname + ' from tableName') -- 请注意 加号前后的 单引号的边上加空格

当然将字符串改成变量的形式也可
declare @fname varchar(20)
set @fname = 'FiledName' --设置字段名
declare @s varchar(1000)
set @s = 'select ' + @fname + ' from tableName'
Exec(@s) -- 成功
exec sp_executesql @s -- 此句会报错

declare @s Nvarchar(1000) -- 注意此处改为nvarchar(1000)
set @s = 'select ' + @fname + ' from tableName'
Exec(@s) -- 成功
exec sp_executesql @s -- 此句正确

3. 输出参数
declare @num int, @sqls nvarchar(4000)
set @sqls='select count(*) from tableName'
exec(@sqls) --如何将exec执行结果放入变量中?

declare @num int, @sqls nvarchar(4000)
set @sqls='select @a=count(*) from tableName '
exec sp_executesql @sqls,N'@a int output',@num output
select @num


使用exec sp_executesql 生成的查询计划会高效, 这是公司Sql规范里的要求, 凡是非字符串的变量, 都要求用这种方式处理

d. 最后再说说那个最长的Select, 不算很复杂. 但也有需要思考过程. 稍微标记下

1. SET @v_Sql = 'INSERT INTO [dbo].'+@v_TmpTableName+'
2. SELECT temp.UserId,temp.MobileNo,mns.Region,temp.LogicalPool
3. FROM [IICHADB].[dbo].[CODE_MobileNoSegment] mns
4. CROSS JOIN (
5. SELECT uca.UserId,uca.MobileNo,uca.LogicalPool
6. FROM ( SELECT UserId,Max(Mid) AS Mid FROM [UMSDB].[dbo].[Task] WHERE TaskStatus = 3 AND DestLogicalPool = @LogicalPoolId 7.         GROUP BY UserId ) t

8.    Inner JOIN [CATDB].[dbo].[CAT_UserCatalogAll] uca ON t.UserId = uca.UserId AND uca.LogicalPool = @LogicalPoolId
9. ) temp
10. WHERE temp.MobileNo BETWEEN mns.BeginNo AND mns.EndNo'
11. EXEC sp_executesql @v_Sql, N'@LogicalPoolId int',@LogicalPoolId

第1行不用多说, 拼Sql

第2,3,4,10行 是要和5,6,7,8,9 行做交叉连接, 因为是交叉连接执行比较慢, 所以想方设法减小两个表的数据量. 同时, 左表通常是数据量较少的表(据说Sql在实际执行时, 默认的会将记录少的表做主表.)

第5,6,7,8,9行实际上是个内连接, CAT_UserCatalogAll是个数据量巨大的表.

第6行的Max(Mid)、Group By UserId 是为了排除重复记录并取最新的记录, 而 TaskStatus 、DestLogicalpool 、uca.LogicalPool都是用来缩小表的数据量的多少.

比较简单, 至于能不能行. 下周DBA说了算, 先这么来吧, 周末了

==== 经过后续测试, 关于本地临时表和全局临时表的问题:

实际在程序中使用的时候, 全局临时表也是不好使的. 当程序执行完存储过程后, 全局临时表也会消失. 最后, 还是用个实体表来当临时表用吧.

参考文献:

可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。
本地临时表的名称前面有一个编号符 (#table_name),而全局临时表的名称前面有两个编号符 (##table_name)。

SQL 语句使用 CREATE TABLE 语句中为 table_name 指定的名称引用临时表:

CREATE TABLE #MyTempTable (cola INT PRIMARY KEY)
INSERT INTO #MyTempTable VALUES (1)

如果本地临时表由存储过程创建或由多个用户同时执行的应用程序创建,则 SQL Server 必须能够区分由不同用户创建的表。为此,SQL Server 在内部为每个本地临时表的表名追加一个数字后缀。存储在 tempdb 数据库的 sysobjects 表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的表名 table_name 不能超过 116 个字符。

除非使用 DROP TABLE 语句显式除去临时表,否则临时表将在退出其作用域时由系统自动除去:

当存储过程完成时,将自动除去在存储过程中创建的本地临时表。由创建表的存储过程执行的所有嵌套存储过程都可以引用此表。但调用创建此表的存储过程的进程无法引用此表。

所有其它本地临时表在当前会话结束时自动除去。

全局临时表在创建此表的会话结束且其它任务停止对其引用时自动除去。任务与表之间的关联只在单个 Transact-SQL 语句的生存周期内保持。换言之,当创建全局临时表的会话结束时,最后一条引用此表的 Transact-SQL 语句完成后,将自动除去此表。
在存储过程或触发器中创建的本地临时表与在调用存储过程或触发器之前创建的同名临时表不同。如果查询引用临时表,而同时有两个同名的临时表,则不定义针对哪个表解析该查询。嵌套存储过程同样可以创建与调用它的存储过程所创建的临时表同名的临时表。嵌套存储过程中对表名的所有引用都被解释为是针对该嵌套过程所创建的表

http://www.cnblogs.com/Hdsome/archive/2008/12/10/1351504.html
/article/4698439.html
/article/4801092.html

#类型临时表的生命周期为当前数据库连接结束

也就是当前链接结束后就自动销毁了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: