SQLSERVER用无中生有的思想来替代游标
SQLSERVER用无中生有的思想来替代游标
SQLSERVER用无中生有的思想来替代游标
昨天在MSDN论坛看到一个帖子,帖子中LZ需要根据某列的值把其他列的值插入到额外列
建表脚本:
USE tempdb
GO
--建表
CREATE TABLE t1
(
client VARCHAR(10) ,
pay_level INT ,
pay_lv_1 INT ,
pay_lv_2 INT ,
pay_lv_3 INT ,
pay_lv_4 INT ,
pay_lv_5 INT ,
pay_lv_6 INT ,
pay_lv_7 INT ,
pay_lv_8 INT ,
pay_lv_9 INT ,
pay_lv_10 INT ,
pay_lv_11 INT ,
pay_lv_12 INT ,
pay_lv_13 INT ,
pay_lv_14 INT ,
pay_lv_15 INT ,
pay_lv_16 INT ,
pay_lv_17 INT ,
pay_lv_18 INT ,
pay_lv_19 INT ,
pay_lv_20 INT ,
pay_lv_21 INT ,
pay_lv_22 INT ,
pay_lv_23 INT ,
pay_lv_24 INT ,
pay_lv_25 INT,
);
--插入测试数据
DECLARE @i INT
SET @i = 1
WHILE @i < 8
BEGIN
INSERT INTO t1 ( client, pay_level, pay_lv_1, pay_lv_2, pay_lv_3,
pay_lv_4, pay_lv_5, pay_lv_6, pay_lv_7, pay_lv_8,
pay_lv_9, pay_lv_10, pay_lv_11, pay_lv_12,
pay_lv_13, pay_lv_14, pay_lv_15, pay_lv_16,
pay_lv_17, pay_lv_18, pay_lv_19, pay_lv_20,
pay_lv_21, pay_lv_22, pay_lv_23, pay_lv_24,
pay_lv_25 )
SELECT 'client' + CAST(@i AS VARCHAR(10)),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND()
SET @i=@i+1
END
SELECT * FROM t1
GO

- 1 USE tempdb
- 2 GO
- 3
- 4 --建表
- 5 CREATE TABLE t1
- 6 (
- 7 client VARCHAR(10) ,
- 8 pay_level INT ,
- 9 pay_lv_1 INT ,
- 10 pay_lv_2 INT ,
- 11 pay_lv_3 INT ,
- 12 pay_lv_4 INT ,
- 13 pay_lv_5 INT ,
- 14 pay_lv_6 INT ,
- 15 pay_lv_7 INT ,
- 16 pay_lv_8 INT ,
- 17 pay_lv_9 INT ,
- 18 pay_lv_10 INT ,
- 19 pay_lv_11 INT ,
- 20 pay_lv_12 INT ,
- 21 pay_lv_13 INT ,
- 22 pay_lv_14 INT ,
- 23 pay_lv_15 INT ,
- 24 pay_lv_16 INT ,
- 25 pay_lv_17 INT ,
- 26 pay_lv_18 INT ,
- 27 pay_lv_19 INT ,
- 28 pay_lv_20 INT ,
- 29 pay_lv_21 INT ,
- 30 pay_lv_22 INT ,
- 31 pay_lv_23 INT ,
- 32 pay_lv_24 INT ,
- 33 pay_lv_25 INT,
- 34 );
- 35
- 36
- 37 --插入测试数据
- 38 DECLARE @i INT
- 39 SET @i = 1
- 40 WHILE @i < 8
- 41 BEGIN
- 42 INSERT INTO t1 ( client, pay_level, pay_lv_1, pay_lv_2, pay_lv_3,
- 43 pay_lv_4, pay_lv_5, pay_lv_6, pay_lv_7, pay_lv_8,
- 44 pay_lv_9, pay_lv_10, pay_lv_11, pay_lv_12,
- 45 pay_lv_13, pay_lv_14, pay_lv_15, pay_lv_16,
- 46 pay_lv_17, pay_lv_18, pay_lv_19, pay_lv_20,
- 47 pay_lv_21, pay_lv_22, pay_lv_23, pay_lv_24,
- 48 pay_lv_25 )
- 49 SELECT 'client' + CAST(@i AS VARCHAR(10)),
- 50 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 51 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 52 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 53 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 54 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 55 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 56 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 57 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 58 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 59 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 60 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 61 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 62 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND()
- 63 SET @i=@i+1
- 64
- 65 END
- 66
- 67 SELECT * FROM t1
- 68 GO

图1
LZ说原表就是类似上面那样,实际表中pay_lv_会有很多列至少100列,我这里为了测试只建了25个pay_lv_列
而LZ希望select出来的结果是下图那样
图2
client列和pay_level列不变,增加一个pay_cost列
pay_cost列根据pay_level列的值去取pay_lv_列的值,或者我用下面的图片会更加明白
图3
例如第6行,pay_level的值是6,那么就去pay_lv_6这一列的值(值是20)把他放到pay_cost列里
其他也是一样,第二行pay_level的值是10,那就去pay_lv_10这一列的值(值是17)把他放到pay_cost列里
如此类推
要select出图2的结果,有下面几种方法
1、case when
2、UNPIVOT函数
3、游标
我这里再建另外一个表,这个表跟原表是一样的,只是数据没有那么多,pay_lv_列数只有3列
USE tempdb
GO
CREATE TABLE #t
(
client VARCHAR(10) ,
pay_level INT ,
pay_lv_1 INT ,
pay_lv_2 INT ,
pay_lv_3 INT
);
INSERT INTO #t ( client ,
pay_level ,
pay_lv_1 ,
pay_lv_2 ,
pay_lv_3
)
VALUES ( 'client1' , -- client - varchar(10)
1, -- pay_level - int
10 , -- pay_lv_1 - int
12 , -- pay_lv_2 - int
14 -- pay_lv_3 - int
)
INSERT INTO #t ( client ,
pay_level ,
pay_lv_1 ,
pay_lv_2 ,
pay_lv_3
)
VALUES ( 'client2' , -- client - varchar(10)
3, -- pay_level - int
21 , -- pay_lv_1 - int
22 , -- pay_lv_2 - int
23 -- pay_lv_3 - int
)
INSERT INTO #t ( client ,
pay_level ,
pay_lv_1 ,
pay_lv_2 ,
pay_lv_3
)
VALUES ( 'client3' , -- client - varchar(10)
2, -- pay_level - int
30 , -- pay_lv_1 - int
32 , -- pay_lv_2 - int
33 -- pay_lv_3 - int
)
SELECT * FROM #t

- 1 USE tempdb
- 2 GO
- 3
- 4
- 5 CREATE TABLE #t
- 6 (
- 7 client VARCHAR(10) ,
- 8 pay_level INT ,
- 9 pay_lv_1 INT ,
- 10 pay_lv_2 INT ,
- 11 pay_lv_3 INT
- 12 );
- 13
- 14 INSERT INTO #t ( client ,
- 15 pay_level ,
- 16 pay_lv_1 ,
- 17 pay_lv_2 ,
- 18 pay_lv_3
- 19 )
- 20 VALUES ( 'client1' , -- client - varchar(10)
- 21 1, -- pay_level - int
- 22 10 , -- pay_lv_1 - int
- 23 12 , -- pay_lv_2 - int
- 24 14 -- pay_lv_3 - int
- 25 )
- 26
- 27
- 28 INSERT INTO #t ( client ,
- 29 pay_level ,
- 30 pay_lv_1 ,
- 31 pay_lv_2 ,
- 32 pay_lv_3
- 33 )
- 34 VALUES ( 'client2' , -- client - varchar(10)
- 35 3, -- pay_level - int
- 36 21 , -- pay_lv_1 - int
- 37 22 , -- pay_lv_2 - int
- 38 23 -- pay_lv_3 - int
- 39 )
- 40
- 41 INSERT INTO #t ( client ,
- 42 pay_level ,
- 43 pay_lv_1 ,
- 44 pay_lv_2 ,
- 45 pay_lv_3
- 46 )
- 47 VALUES ( 'client3' , -- client - varchar(10)
- 48 2, -- pay_level - int
- 49 30 , -- pay_lv_1 - int
- 50 32 , -- pay_lv_2 - int
- 51 33 -- pay_lv_3 - int
- 52 )
- 53
- 54 SELECT * FROM #t

(1)case when

- 1 SELECT client,[pay_level],( CASE pay_level
- 2 WHEN 1 THEN pay_lv_1
- 3 WHEN 2 THEN pay_lv_2
- 4 WHEN 3 THEN pay_lv_3
- 5 ELSE 0
- 6 END) AS 'pay_cost'
- 7 FROM #t;

图4
(2)UNPIVOT函数

- 1 SELECT * INTO #tt
- 2 FROM ( SELECT *
- 3 FROM #t
- 4 ) p UNPIVOT
- 5 ( pay_cost FOR pay_lv IN ( pay_lv_1, pay_lv_2, pay_lv_3 ) )AS unpvt
- 6 WHERE CAST(RIGHT(pay_lv, 1) AS INT) = pay_level
- 7
- 8 SELECT [client],[pay_level],[pay_cost] FROM [#tt]
- 9
- 10 DROP TABLE [#tt]

图5
上面两个方法:CASE WHEN和UNPIVOT函数可以用拼接SQL的方法来做,不过由于本人功力不够,写不出来
(3)游标
我不喜欢使用游标,主要有两个原因
1、每次用的时候,要打开笔记本看语法
2、占用资源
我使用了下面的sql语句来解决LZ的问题
IF object_id('#ttt') IS NOT NULL
DROP TABLE #ttt
IF object_id('#temptb') IS NOT NULL
DROP TABLE #temptb
DECLARE @i INT
--用于循环的
SET @i = 1
DECLARE @pay_level INT
--保存pay_level字段的值
DECLARE @COUNT INT
--保存#t1表的总行数值
DECLARE @pay_lv INT
--用于保存pay_lv的值
DECLARE @sql NVARCHAR(2000)
CREATE TABLE #ttt (ID INT IDENTITY(1,1), pay_cost INT )
SELECT IDENTITY( INT,1,1 ) AS ID, * INTO #temptb FROM t1
--获取#t1表的总行数
SELECT @COUNT = COUNT(*) FROM [#temptb]
WHILE @i <= @COUNT
BEGIN
SELECT @pay_level = [pay_level] FROM [#temptb] WHERE id = @i
--判断列名是否存在,不存在就插入0
IF 'pay_lv_' + CAST(@pay_level AS VARCHAR(200)) IN ( SELECT NAME FROM SYS.[syscolumns] )
BEGIN
--用拼接sql的方法来获得pay_lv列对应的值,然后插入到#ttt表
SET @sql = N'select ' + ' @pay_lv=pay_lv_' + CAST(@pay_level AS NVARCHAR(200)) + ' from #temptb where id=' + CAST(@i AS NVARCHAR(20))
EXEC sp_executesql @sql, N'@pay_lv int output ', @pay_lv OUTPUT
INSERT INTO #ttt VALUES (@pay_lv)
END
ELSE
BEGIN
INSERT INTO #ttt VALUES(0)
END
SET @i = @i + 1
END
SELECT A.[client], A.[pay_level], B.[pay_cost]
FROM [#temptb] AS A
INNER JOIN [#ttt] AS B ON A.[ID] = B.[ID]
ORDER BY A.[ID] ASC
DROP TABLE [#temptb]
DROP TABLE [#ttt]

- 1 IF object_id('#ttt') IS NOT NULL
- 2 DROP TABLE #ttt
- 3 IF object_id('#temptb') IS NOT NULL
- 4 DROP TABLE #temptb
- 5
- 6 DECLARE @i INT
- 7 --用于循环的
- 8 SET @i = 1
- 9 DECLARE @pay_level INT
- 10 --保存pay_level字段的值
- 11 DECLARE @COUNT INT
- 12 --保存#t1表的总行数值
- 13 DECLARE @pay_lv INT
- 14 --用于保存pay_lv的值
- 15 DECLARE @sql NVARCHAR(2000)
- 16
- 17 CREATE TABLE #ttt (ID INT IDENTITY(1,1), pay_cost INT )
- 18
- 19 SELECT IDENTITY( INT,1,1 ) AS ID, * INTO #temptb FROM t1
- 20
- 21
- 22 --获取#t1表的总行数
- 23 SELECT @COUNT = COUNT(*) FROM [#temptb]
- 24 WHILE @i <= @COUNT
- 25 BEGIN
- 26 SELECT @pay_level = [pay_level] FROM [#temptb] WHERE id = @i
- 27 --判断列名是否存在,不存在就插入0
- 28 IF 'pay_lv_' + CAST(@pay_level AS VARCHAR(200)) IN ( SELECT NAME FROM SYS.[syscolumns] )
- 29 BEGIN
- 30 --用拼接sql的方法来获得pay_lv列对应的值,然后插入到#ttt表
- 31 SET @sql = N'select ' + ' @pay_lv=pay_lv_' + CAST(@pay_level AS NVARCHAR(200)) + ' from #temptb where id=' + CAST(@i AS NVARCHAR(20))
- 32 EXEC sp_executesql @sql, N'@pay_lv int output ', @pay_lv OUTPUT
- 33 INSERT INTO #ttt VALUES (@pay_lv)
- 34 END
- 35 ELSE
- 36 BEGIN
- 37 INSERT INTO #ttt VALUES(0)
- 38 END
- 39 SET @i = @i + 1
- 40 END
- 41
- 42
- 43
- 44 SELECT A.[client], A.[pay_level], B.[pay_cost]
- 45 FROM [#temptb] AS A
- 46 INNER JOIN [#ttt] AS B ON A.[ID] = B.[ID]
- 47 ORDER BY A.[ID] ASC
- 48
- 49 DROP TABLE [#temptb]
- 50 DROP TABLE [#ttt]

我这个sql语句也需要拼接sql来达到LZ想要的效果
不过这篇文章的重点不是拼接SQL
重点是怎麽模仿游标
其实这个方法是最原始的方法,之前解决论坛问题的时候用过,想不到这次也能用上
USE tempdb
GO
--建表
CREATE TABLE t1
(
client VARCHAR(10) ,
pay_level INT ,
pay_lv_1 INT ,
pay_lv_2 INT ,
pay_lv_3 INT ,
pay_lv_4 INT ,
pay_lv_5 INT ,
pay_lv_6 INT ,
pay_lv_7 INT ,
pay_lv_8 INT ,
pay_lv_9 INT ,
pay_lv_10 INT ,
pay_lv_11 INT ,
pay_lv_12 INT ,
pay_lv_13 INT ,
pay_lv_14 INT ,
pay_lv_15 INT ,
pay_lv_16 INT ,
pay_lv_17 INT ,
pay_lv_18 INT ,
pay_lv_19 INT ,
pay_lv_20 INT ,
pay_lv_21 INT ,
pay_lv_22 INT ,
pay_lv_23 INT ,
pay_lv_24 INT ,
pay_lv_25 INT,
);
--插入测试数据
DECLARE @i INT
SET @i = 1
WHILE @i < 8
BEGIN
INSERT INTO t1 ( client, pay_level, pay_lv_1, pay_lv_2, pay_lv_3,
pay_lv_4, pay_lv_5, pay_lv_6, pay_lv_7, pay_lv_8,
pay_lv_9, pay_lv_10, pay_lv_11, pay_lv_12,
pay_lv_13, pay_lv_14, pay_lv_15, pay_lv_16,
pay_lv_17, pay_lv_18, pay_lv_19, pay_lv_20,
pay_lv_21, pay_lv_22, pay_lv_23, pay_lv_24,
pay_lv_25 )
SELECT 'client' + CAST(@i AS VARCHAR(10)),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND()
SET @i=@i+1
END
SELECT * FROM t1
GO
--ALTER TABLE [t1] DROP COLUMN [pay_lv_2]
-----------------------------------------------------
IF object_id('#ttt') IS NOT NULL
DROP TABLE #ttt
IF object_id('#temptb') IS NOT NULL
DROP TABLE #temptb
DECLARE @i INT
--用于循环的
SET @i = 1
DECLARE @pay_level INT
--保存pay_level字段的值
DECLARE @COUNT INT
--保存t1表的总行数值
DECLARE @pay_lv INT
--用于保存pay_lv的值
DECLARE @sql NVARCHAR(2000)
CREATE TABLE #ttt (ID INT IDENTITY(1,1), pay_cost INT )
SELECT IDENTITY( INT,1,1 ) AS ID, * INTO #temptb FROM t1
--获取t1表的总行数
SELECT @COUNT = COUNT(*) FROM [#temptb]
WHILE @i <= @COUNT
BEGIN
SELECT @pay_level = [pay_level] FROM [#temptb] WHERE id = @i
--判断列名是否存在,不存在就插入0
IF 'pay_lv_' + CAST(@pay_level AS VARCHAR(200)) IN ( SELECT NAME FROM SYS.[syscolumns] )
BEGIN
--用拼接sql的方法来获得pay_lv列对应的值,然后插入到#ttt表
SET @sql = N'select ' + ' @pay_lv=pay_lv_' + CAST(@pay_level AS NVARCHAR(200)) + ' from #temptb where id=' + CAST(@i AS NVARCHAR(20))
EXEC sp_executesql @sql, N'@pay_lv int output ', @pay_lv OUTPUT
INSERT INTO #ttt VALUES (@pay_lv)
END
ELSE
BEGIN
INSERT INTO #ttt VALUES(0)
END
SET @i = @i + 1
END
SELECT A.[client], A.[pay_level], B.[pay_cost]
FROM [#temptb] AS A
INNER JOIN [#ttt] AS B ON A.[ID] = B.[ID]
ORDER BY A.[ID] ASC
DROP TABLE [#temptb]
DROP TABLE [#ttt]

- 1 USE tempdb
- 2 GO
- 3
- 4 --建表
- 5 CREATE TABLE t1
- 6 (
- 7 client VARCHAR(10) ,
- 8 pay_level INT ,
- 9 pay_lv_1 INT ,
- 10 pay_lv_2 INT ,
- 11 pay_lv_3 INT ,
- 12 pay_lv_4 INT ,
- 13 pay_lv_5 INT ,
- 14 pay_lv_6 INT ,
- 15 pay_lv_7 INT ,
- 16 pay_lv_8 INT ,
- 17 pay_lv_9 INT ,
- 18 pay_lv_10 INT ,
- 19 pay_lv_11 INT ,
- 20 pay_lv_12 INT ,
- 21 pay_lv_13 INT ,
- 22 pay_lv_14 INT ,
- 23 pay_lv_15 INT ,
- 24 pay_lv_16 INT ,
- 25 pay_lv_17 INT ,
- 26 pay_lv_18 INT ,
- 27 pay_lv_19 INT ,
- 28 pay_lv_20 INT ,
- 29 pay_lv_21 INT ,
- 30 pay_lv_22 INT ,
- 31 pay_lv_23 INT ,
- 32 pay_lv_24 INT ,
- 33 pay_lv_25 INT,
- 34 );
- 35
- 36
- 37 --插入测试数据
- 38 DECLARE @i INT
- 39 SET @i = 1
- 40 WHILE @i < 8
- 41 BEGIN
- 42 INSERT INTO t1 ( client, pay_level, pay_lv_1, pay_lv_2, pay_lv_3,
- 43 pay_lv_4, pay_lv_5, pay_lv_6, pay_lv_7, pay_lv_8,
- 44 pay_lv_9, pay_lv_10, pay_lv_11, pay_lv_12,
- 45 pay_lv_13, pay_lv_14, pay_lv_15, pay_lv_16,
- 46 pay_lv_17, pay_lv_18, pay_lv_19, pay_lv_20,
- 47 pay_lv_21, pay_lv_22, pay_lv_23, pay_lv_24,
- 48 pay_lv_25 )
- 49 SELECT 'client' + CAST(@i AS VARCHAR(10)),
- 50 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 51 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 52 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 53 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 54 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 55 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 56 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 57 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 58 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 59 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 60 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 61 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND(),
- 62 ( 20 + 1 ) * RAND(), ( 20 + 1 ) * RAND()
- 63 SET @i=@i+1
- 64
- 65 END
- 66
- 67 SELECT * FROM t1
- 68 GO
- 69
- 70 --ALTER TABLE [t1] DROP COLUMN [pay_lv_2]
- 71
- 72
- 73 -----------------------------------------------------
- 74 IF object_id('#ttt') IS NOT NULL
- 75 DROP TABLE #ttt
- 76 IF object_id('#temptb') IS NOT NULL
- 77 DROP TABLE #temptb
- 78
- 79 DECLARE @i INT
- 80 --用于循环的
- 81 SET @i = 1
- 82 DECLARE @pay_level INT
- 83 --保存pay_level字段的值
- 84 DECLARE @COUNT INT
- 85 --保存t1表的总行数值
- 86 DECLARE @pay_lv INT
- 87 --用于保存pay_lv的值
- 88 DECLARE @sql NVARCHAR(2000)
- 89
- 90 CREATE TABLE #ttt (ID INT IDENTITY(1,1), pay_cost INT )
- 91
- 92 SELECT IDENTITY( INT,1,1 ) AS ID, * INTO #temptb FROM t1
- 93
- 94
- 95 --获取t1表的总行数
- 96 SELECT @COUNT = COUNT(*) FROM [#temptb]
- 97 WHILE @i <= @COUNT
- 98 BEGIN
- 99 SELECT @pay_level = [pay_level] FROM [#temptb] WHERE id = @i
- 100 --判断列名是否存在,不存在就插入0
- 101 IF 'pay_lv_' + CAST(@pay_level AS VARCHAR(200)) IN ( SELECT NAME FROM SYS.[syscolumns] )
- 102 BEGIN
- 103 --用拼接sql的方法来获得pay_lv列对应的值,然后插入到#ttt表
- 104 SET @sql = N'select ' + ' @pay_lv=pay_lv_' + CAST(@pay_level AS NVARCHAR(200)) + ' from #temptb where id=' + CAST(@i AS NVARCHAR(20))
- 105 EXEC sp_executesql @sql, N'@pay_lv int output ', @pay_lv OUTPUT
- 106 INSERT INTO #ttt VALUES (@pay_lv)
- 107 END
- 108 ELSE
- 109 BEGIN
- 110 INSERT INTO #ttt VALUES(0)
- 111 END
- 112 SET @i = @i + 1
- 113 END
- 114
- 115
- 116
- 117 SELECT A.[client], A.[pay_level], B.[pay_cost]
- 118 FROM [#temptb] AS A
- 119 INNER JOIN [#ttt] AS B ON A.[ID] = B.[ID]
- 120 ORDER BY A.[ID] ASC
- 121
- 122 DROP TABLE [#temptb]
- 123 DROP TABLE [#ttt]

关键代码有以下几句

- 1 CREATE TABLE #ttt (ID INT IDENTITY(1,1), pay_cost INT )
- 2
- 3 SELECT IDENTITY( INT,1,1 ) AS ID, * INTO #temptb FROM t1
- 4
- 5 --获取#t1表的总行数
- 6 SELECT @COUNT = COUNT(*) FROM [#temptb]
- 7 WHILE @i <= @COUNT
- 8 SELECT @pay_level = [pay_level] FROM [#temptb] WHERE id = @i
- 9 SET @i = @i + 1
- 10 ----------------------------------
- 11 SELECT A.[client], A.[pay_level], B.[pay_cost]
- 12 FROM [#temptb] AS A
- 13 INNER JOIN [#ttt] AS B ON A.[ID] = B.[ID]
- 14 ORDER BY A.[ID] ASC

原表是没有自增id的,我建一个临时表#temptb,临时表有一个自增id,并把原表的数据全部放入临时表
获取临时表的行数,用于循环
每次执行的时候根据 WHERE id = @i 来逐行逐行获取值,变量@i每次循环都递增1
将获取到的值都插入到#ttt这个临时表里面,然后根据ID的值做两表连接就可以得到LZ的结果
我说的无中生有就是“在原表里增加一个自增id方便循环,既简单又容易理解o(∩_∩)o ”
判断
我这里还用了一句
- 1 IF 'pay_lv_' + CAST(@pay_level AS VARCHAR(200)) IN ( SELECT NAME FROM SYS.[syscolumns] )
用于判断要获取值的pay_lv_列是否存在,如果存在就插入pay_lv_列的值,如果不存在就插入0
总结
其实如果觉得某样东西很难去实现,能不能用一个变通的方法呢?多动脑筋,办法会有的
如有不对的地方,欢迎大家拍砖o(∩_∩)o
SQLSERVER用无中生有的思想来替代游标的更多相关文章
- SQL优化技巧-批处理替代游标
通过MSSQL中的用户自定义表类型可以快速将需要处理的数据存储起来,生成新的临时表(这里使用变量表),然后根据表中字段进行批处理替代游标. 用户自定义表类型 0 --创建用户自定义表类型 1 Crea ...
- SQL Server 中用While循环替代游标Cursor的解决方案
在编写SQL批处理或存储过程代码的过程中,经常会碰到有些业务逻辑的处理,需要对满足条件的数据记录逐行进行处理,这个时候,大家首先想到的方案大部分是用“游标”进行处理. 举个例子,在订单管理系统中,客服 ...
- SqlServer 临时表、表变量、函数 替代游标
http://www.cnblogs.com/chongzi/archive/2011/01/19/1939106.html 临时表 存放在tempdb中 --存储过程中将多表连接结果写入到临时表中, ...
- [转]SQL Server中用While循环替代游标(Cursor)的解决方案
本文转自:https://www.cnblogs.com/SunnyZhu/p/5719184.html By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行 ...
- SQL Server中用While循环替代游标(Cursor)的解决方案
By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行数据分别需要多长时间. 一.游标. 首先我们填充一个表,用优雅的递归方式填充. ,) ) ;with ct ...
- sqlserver数据库安全函数、配置函数、游标函数、行级函数、排名函数、元数据函数、系统统计函数 、文本和图像函数--收藏着有用
行级函数:下列行集函数将返回一个可用于代替 Transact-SQL 语句中表引用的对象. CONTAINSTABLE 返回具有零行.一行或多行的表,这些行的列中包含的基于字符类型的数据是单个词语和短 ...
- SQL 临时表或表变量替代游标
1.如果表没有自动增长的标识列(int) 使用临时表 SELECT IDENTITY(int) NewID ,.. INTO #tmp FROM YouTable 2.表有标识列 使用表变量 INSE ...
- SQL 临时表或表变量替代游标(转)
1.如果表没有自动增长的标识列(int) 使用临时表 SELECT IDENTITY(int) NewID ,.. INTO #tmp FROM YouTable 2.表有标识列 使用表变量 INSE ...
- sqlserver临时表或表变量代替游标
在很多场合,用临时表或表变量也可以替代游标 临时表用在表没有标识列(int)的情况下. 在表有标识列(int)的情况下可以用表变量,当然也可以用临时表. 利用临时表或表变量的原因时,生成一个连续的列 ...
随机推荐
- C# 程序自动批量生成 google maps 的KML文件
原文:C# 程序自动批量生成 google maps 的KML文件 google maps 的 KML 文件可以用于静态的地图标注,在某些应用中,我们手上往往有成百上千个地址,我们需要把这些地址和描述 ...
- MVC 6 写法
MVC 6 一些不晓得的写法 今天在看 Scott Guthrie 的一篇博文<Introducing ASP.NET 5>,在 MVC 6 中,发现有些之前不晓得的写法,这边简单记录下, ...
- Thrift官方安装手冊(译)
本篇是Thrift官网安装文档的翻译,原地址点击这里.Thrift之前是不支持Windows的.可是似乎0.9版本号以后已经支持Window了.介绍了Thrift安装的环境要求以及在centos,De ...
- 日期格式化{0:yyyy-MM-dd HH:mm:ss.fff}和{0:yyyy-MM-dd hh:mm:ss.fff}的区别
原文:日期格式化{0:yyyy-MM-dd HH:mm:ss.fff}和{0:yyyy-MM-dd hh:mm:ss.fff}的区别 {0:yyyy-MM-dd HH:mm:ss.fff}:使用24小 ...
- 如何判断微信内置浏览器(通过User Agent实现)
在进行微信公众账号开发的时候,其中很大一块是微站点的开发,我们需要知道当前的浏览器是微信内置的浏览器,那么如何判断呢? 微信内置浏览器的 User Agent 如何判断微信内置浏览器,首先需要获取微信 ...
- 为Pythonic论坛添加一个“专题”功能
代码还没读完就踏上了修改功能的深坑.还好思路清晰,通过修改模板和视图,实现了专题模块 原论坛的模式是用户点击节点发帖,然后就归到节点的分类里面了.我需要一个功能,就是右侧需要一个专题区,管理员发帖的话 ...
- Kindle使用技巧
Kindle使用技巧 使用kindle也有几年了,但是好多kindle的使用技巧还不知道,在网上看到了一些,整理了一下. 1. 格式转换 把PDF发送到Kindle的时候,邮件主题写convert,这 ...
- 我看PS求职简历照
看新闻<大学生求职简历照片不PS 连面试机会都没有>,忍不住也谈些自己的看法. 个人意见,尽量求真,这个求真要有平时努力的保证.长相一般的,知道自己是普通一员,按普通的方式行事就可以.即使 ...
- 算法课上机实验(一个简单的GUI排序算法比较程序)
(在家里的电脑上Linux Deepin截的图,屏幕大一点的话,deepin用着还挺不错的说) 这个应该是大二的算法课程上机实验时做的一个小程序,也是我的第一个GUI小程序,实现什么的都记不清了,只记 ...
- 【转】 Android项目的mvc模式
MVC (Model-View-Controller):M是指逻辑模型,V是指视图模型,C则是控制器.一个逻辑模型M可以对于多种视图模型V,比如一批统计数据你可以分别用柱状图.饼图V来表示.一种视图模 ...