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. mysql 打开远程服务

    进mysqlserver 例如下列: Enter password: ****** Welcome to the MySQL monitor.  Commands end with ; or \g. ...

  2. 【百度地图API】自行获取区域经纬度的工具

    原文:[百度地图API]自行获取区域经纬度的工具 摘要:上一章教大家如何建立自己的行政区域地图.这次为大家提供一个,可视化选择区域,并且能自动生成经纬度代码的工具.工具的源代码完全公开,并且做了详尽的 ...

  3. 浅谈 js 数字格式类型

    原文:浅谈 js 数字格式类型 很多人也许只知道 ,123.456,0xff 之类的数字格式.其实 js 格式还有很多数字格式类型,比如 1., .1 这样的,也有 .1e2 这样的. 可能有人说这是 ...

  4. HDU 4006 The kth great number AVL解

    提供动态更新数据.第实时QK大量的值什么? 使用AVL统计数据结构做,比较先进的数据结构的内容. 不知道给出的数据为准值是否有反复.下面的程序是因为我能够处理重复数据出现的情况下,. 了repeat的 ...

  5. pinyin4j新手教程

    Pinyin4j新手教程 pinyin4j是一个支持将简体和繁体中文转换到成拼音的Java开源类库,作者是Li Min (xmlerlimin@gmail.com). 下面是一些详细的介绍和使用方式. ...

  6. 谈论quick-cocos2d-x和cocos2d-x lua了解差异

    之前说,我把这个两个词区别.经过太长时间.当然,反击的麻烦.quick-cocos2d-x它提到quick,cocos2d-x lua姑且称为本地lua对. 我认为,首先与这两个小的朋友接触会跟着或多 ...

  7. linux 定时关机命令

    一. 关机流程 Linux 运作时, 不能够直接将电源关闭, 否则, 可能会损毁档案系统. 因此, 必须依照正常的程序关机: 观察系统使用情形(或许当时, 正有使用者做着重要的工作呢!) 通知线上使用 ...

  8. SQL点滴20—T-SQL中的排名函数

    原文:SQL点滴20-T-SQL中的排名函数 提到排名函数我们首先可能想到的是order by,这个是排序,不是排名,排名需要在前面加个名次序号的,order by是没有这个功能的.还可能会想到ide ...

  9. 在项目管理工具Redmine中使用SubVersion进行版本管理

    原文:在项目管理工具Redmine中使用SubVersion进行版本管理 在项目管理工具Redmine中使用SubVersion进行版本管理 分类: Redmine2009-06-01 10:11 5 ...

  10. javascript 学习总结(三)Boolean对象

    Boolean对象 /* 创建 Boolean 对象的语法: new Boolean(value); //构造函数 Boolean(value); //转换函数 参数 value 由布尔对象存放的值或 ...