SQLSERVER用无中生有的思想来替代游标

SQLSERVER用无中生有的思想来替代游标

昨天在MSDN论坛看到一个帖子,帖子中LZ需要根据某列的值把其他列的值插入到额外列

帖子地址:http://social.technet.microsoft.com/Forums/zh-CN/3eac78ca-d071-4c00-afa0-ef48c8501745/sql-statementcolumn-namecolumnsql-


建表脚本

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用无中生有的思想来替代游标的更多相关文章

  1. SQL优化技巧-批处理替代游标

    通过MSSQL中的用户自定义表类型可以快速将需要处理的数据存储起来,生成新的临时表(这里使用变量表),然后根据表中字段进行批处理替代游标. 用户自定义表类型 0 --创建用户自定义表类型 1 Crea ...

  2. SQL Server 中用While循环替代游标Cursor的解决方案

    在编写SQL批处理或存储过程代码的过程中,经常会碰到有些业务逻辑的处理,需要对满足条件的数据记录逐行进行处理,这个时候,大家首先想到的方案大部分是用“游标”进行处理. 举个例子,在订单管理系统中,客服 ...

  3. SqlServer 临时表、表变量、函数 替代游标

    http://www.cnblogs.com/chongzi/archive/2011/01/19/1939106.html 临时表 存放在tempdb中 --存储过程中将多表连接结果写入到临时表中, ...

  4. [转]SQL Server中用While循环替代游标(Cursor)的解决方案

    本文转自:https://www.cnblogs.com/SunnyZhu/p/5719184.html By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行 ...

  5. SQL Server中用While循环替代游标(Cursor)的解决方案

    By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行数据分别需要多长时间. 一.游标. 首先我们填充一个表,用优雅的递归方式填充. ,) ) ;with ct ...

  6. sqlserver数据库安全函数、配置函数、游标函数、行级函数、排名函数、元数据函数、系统统计函数 、文本和图像函数--收藏着有用

    行级函数:下列行集函数将返回一个可用于代替 Transact-SQL 语句中表引用的对象. CONTAINSTABLE 返回具有零行.一行或多行的表,这些行的列中包含的基于字符类型的数据是单个词语和短 ...

  7. SQL 临时表或表变量替代游标

    1.如果表没有自动增长的标识列(int) 使用临时表 SELECT IDENTITY(int) NewID ,.. INTO #tmp FROM YouTable 2.表有标识列 使用表变量 INSE ...

  8. SQL 临时表或表变量替代游标(转)

    1.如果表没有自动增长的标识列(int) 使用临时表 SELECT IDENTITY(int) NewID ,.. INTO #tmp FROM YouTable 2.表有标识列 使用表变量 INSE ...

  9. sqlserver临时表或表变量代替游标

    在很多场合,用临时表或表变量也可以替代游标 临时表用在表没有标识列(int)的情况下. 在表有标识列(int)的情况下可以用表变量,当然也可以用临时表. 利用临时表或表变量的原因时,生成一个连续的列 ...

随机推荐

  1. 【Stackoverflow好问题】java在,如何推断阵列Array是否包括指定的值

    问题 java中,怎样推断数组Array是否包括指定的值 精华回答 1. Arrays.asList(...).contains(...) 2. 使用 Apache Commons Lang包中的Ar ...

  2. MVC Bootstrap Helpers

    ASP.NET MVC Bootstrap Helpers   阅读目录 序言 内置的HTML Helpers 创建自定义的Helpers 使用静态方法创建Helpers 使用扩展方法创建Helper ...

  3. 安装 CocoaPods & Alcatraz

    (一)安装CocoaPods { CocoaPods :} 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使 ...

  4. ResultSet 转为 List或者JavaBean

    一.将ResultSet结果集转换为List,其中每条记录信息保存为Map放到List中,方法如下: public static List<Map<String, Object>&g ...

  5. WebBrowser控件使用技巧分享

    原文:WebBrowser控件使用技巧分享 在发布“淘宝登货员”时发现不少朋友对WebBrowser控件比较感兴趣,故在此分享一下使用心得. 首先分享一个WebBrowser的扩展类(此类所需的dll ...

  6. vim跳转

    w 跳到下一个单词的开始 e 跳到单词的结束 b 向后跳 gg 跳到文件的开始 G 跳到文件的结束 10gg 或10G 跳到第10行 ta 跳到下一个a 前面 fa 跳到下一个a 大写的意思相反 另外 ...

  7. jQuery 添加 删除 改动select option

    jQuery获取Select选择的Text和Value: 1. var checkText=jQuery("#select_id").find("option:selec ...

  8. 微软不也是从Altair Basic这丑小鸭长成白天鹅吗?

    微软不也是从Altair Basic这丑小鸭长成白天鹅吗? February 2015 如果你想要弄清楚初创企业是怎么一回事的话,其中一个非常有价值的尝试是去研究下那些获得巨大成功的公司,去分析下为什 ...

  9. Linux C 多线程

    原文:Linux C 多线程 linux下C语言多线程编程 #include <pthread.h> #include <stdio.h> #include <sys/t ...

  10. SQL data reader reading data performance test

    /*Author: Jiangong SUN*/ As I've manipulated a lot of data using SQL data reader in recent project. ...