1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
--按某一字段分组取最大(小)值所在行的数据
--(爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-10-23于浙江杭州)
/*
数据如下:
name
val memo
a 2 a2(a的第二个值)
a 1 a1
--a的第一个值
a 3 a3:a的第三个值
b 1 b1
--b的第一个值
b 3 b3:b的第三个值
b 2 b2b2b2b2
b 4 b4b4
b 5 b5b5b5b5b5
*/
--创建表并插入数据:
create
table
tb(
name
varchar
(10),val
int
,memo
varchar
(20))
insert
into
tb
values
(
'a'
, 2,
'a2(a的第二个值)'
)
insert
into
tb
values
(
'a'
, 1,
'a1--a的第一个值'
)
insert
into
tb
values
(
'a'
, 3,
'a3:a的第三个值'
)
insert
into
tb
values
(
'b'
, 1,
'b1--b的第一个值'
)
insert
into
tb
values
(
'b'
, 3,
'b3:b的第三个值'
)
insert
into
tb
values
(
'b'
, 2,
'b2b2b2b2'
)
insert
into
tb
values
(
'b'
, 4,
'b4b4'
)
insert
into
tb
values
(
'b'
, 5,
'b5b5b5b5b5'
)
go
--一、按name分组取val最大的值所在行的数据。
--方法1:
select
a.*
from
tb a
where
val = (
select
max
(val)
from
tb
where
name
= a.
name
)
order
by
a.
name
--方法2:
select
a.*
from
tb a
where
not
exists(
select
1
from
tb
where
name
= a.
name
and
val > a.val)
--方法3:
select
a.*
from
tb a,(
select
name
,
max
(val) val
from
tb
group
by
name
) b
where
a.
name
= b.
name
and
a.val = b.val
order
by
a.
name
--方法4:
select
a.*
from
tb a
inner
join
(
select
name
,
max
(val) val
from
tb
group
by
name
) b
on
a.
name
= b.
name
and
a.val = b.val
order
by
a.
name
--方法5
select
a.*
from
tb a
where
1 > (
select
count
(*)
from
tb
where
name
= a.
name
and
val > a.val )
order
by
a.
name
/*
name
val memo
---------- ----------- --------------------
a 3 a3:a的第三个值
b 5 b5b5b5b5b5
*/
--二、按name分组取val最小的值所在行的数据。
--方法1:
select
a.*
from
tb a
where
val = (
select
min
(val)
from
tb
where
name
= a.
name
)
order
by
a.
name
--方法2:
select
a.*
from
tb a
where
not
exists(
select
1
from
tb
where
name
= a.
name
and
val < a.val)
--方法3:
select
a.*
from
tb a,(
select
name
,
min
(val) val
from
tb
group
by
name
) b
where
a.
name
= b.
name
and
a.val = b.val
order
by
a.
name
--方法4:
select
a.*
from
tb a
inner
join
(
select
name
,
min
(val) val
from
tb
group
by
name
) b
on
a.
name
= b.
name
and
a.val = b.val
order
by
a.
name
--方法5
select
a.*
from
tb a
where
1 > (
select
count
(*)
from
tb
where
name
= a.
name
and
val < a.val)
order
by
a.
name
/*
name
val memo
---------- ----------- --------------------
a 1 a1
--a的第一个值
b 1 b1
--b的第一个值
*/
--三、按name分组取第一次出现的行所在的数据。
select
a.*
from
tb a
where
val = (
select
top
1 val
from
tb
where
name
= a.
name
)
order
by
a.
name
/*
name
val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
b 1 b1
--b的第一个值
*/
--四、按name分组随机取一条数据。
select
a.*
from
tb a
where
val = (
select
top
1 val
from
tb
where
name
= a.
name
order
by
newid())
order
by
a.
name
/*
name
val memo
---------- ----------- --------------------
a 1 a1
--a的第一个值
b 5 b5b5b5b5b5
*/
--五、按name分组取最小的两个(N个)val
select
a.*
from
tb a
where
2 > (
select
count
(*)
from
tb
where
name
= a.
name
and
val < a.val )
order
by
a.
name
,a.val
select
a.*
from
tb a
where
val
in
(
select
top
2 val
from
tb
where
name
=a.
name
order
by
val)
order
by
a.
name
,a.val
select
a.*
from
tb a
where
exists (
select
count
(*)
from
tb
where
name
= a.
name
and
val < a.val
having
Count
(*) < 2)
order
by
a.
name
,a.val
/*
name
val memo
---------- ----------- --------------------
a 1 a1
--a的第一个值
a 2 a2(a的第二个值)
b 1 b1
--b的第一个值
b 2 b2b2b2b2
*/
--六、按name分组取最大的两个(N个)val
select
a.*
from
tb a
where
2 > (
select
count
(*)
from
tb
where
name
= a.
name
and
val > a.val )
order
by
a.
name
,a.val
select
a.*
from
tb a
where
val
in
(
select
top
2 val
from
tb
where
name
=a.
name
order
by
val
desc
)
order
by
a.
name
,a.val
select
a.*
from
tb a
where
exists (
select
count
(*)
from
tb
where
name
= a.
name
and
val > a.val
having
Count
(*) < 2)
order
by
a.
name
, a.val
/*
name
val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
a 3 a3:a的第三个值
b 4 b4b4
b 5 b5b5b5b5b5
*/
--七,如果整行数据有重复,所有的列都相同。
/*
数据如下:
name
val memo
a 2 a2(a的第二个值)
a 1 a1
--a的第一个值
a 1 a1
--a的第一个值
a 3 a3:a的第三个值
a 3 a3:a的第三个值
b 1 b1
--b的第一个值
b 3 b3:b的第三个值
b 2 b2b2b2b2
b 4 b4b4
b 5 b5b5b5b5b5
*/
--在sql server 2000中只能用一个临时表来解决,生成一个自增列,先对val取最大或最小,然后再通过自增列来取数据。
--创建表并插入数据:
create
table
tb(
name
varchar
(10),val
int
,memo
varchar
(20))
insert
into
tb
values
(
'a'
, 2,
'a2(a的第二个值)'
)
insert
into
tb
values
(
'a'
, 1,
'a1--a的第一个值'
)
insert
into
tb
values
(
'a'
, 1,
'a1--a的第一个值'
)
insert
into
tb
values
(
'a'
, 3,
'a3:a的第三个值'
)
insert
into
tb
values
(
'a'
, 3,
'a3:a的第三个值'
)
insert
into
tb
values
(
'b'
, 1,
'b1--b的第一个值'
)
insert
into
tb
values
(
'b'
, 3,
'b3:b的第三个值'
)
insert
into
tb
values
(
'b'
, 2,
'b2b2b2b2'
)
insert
into
tb
values
(
'b'
, 4,
'b4b4'
)
insert
into
tb
values
(
'b'
, 5,
'b5b5b5b5b5'
)
go
select
* , px = identity(
int
,1,1)
into
tmp
from
tb
select
m.
name
,m.val,m.memo
from
(
select
t.*
from
tmp t
where
val = (
select
min
(val)
from
tmp
where
name
= t.
name
)
) m
where
px = (
select
min
(px)
from
(
select
t.*
from
tmp t
where
val = (
select
min
(val)
from
tmp
where
name
= t.
name
)
) n
where
n.
name
= m.
name
)
drop
table
tb,tmp
/*
name
val memo
---------- ----------- --------------------
a 1 a1
--a的第一个值
b 1 b1
--b的第一个值
(2 行受影响)
*/
--在sql server 2005中可以使用row_number函数,不需要使用临时表。
--创建表并插入数据:
create
table
tb(
name
varchar
(10),val
int
,memo
varchar
(20))
insert
into
tb
values
(
'a'
, 2,
'a2(a的第二个值)'
)
insert
into
tb
values
(
'a'
, 1,
'a1--a的第一个值'
)
insert
into
tb
values
(
'a'
, 1,
'a1--a的第一个值'
)
insert
into
tb
values
(
'a'
, 3,
'a3:a的第三个值'
)
insert
into
tb
values
(
'a'
, 3,
'a3:a的第三个值'
)
insert
into
tb
values
(
'b'
, 1,
'b1--b的第一个值'
)
insert
into
tb
values
(
'b'
, 3,
'b3:b的第三个值'
)
insert
into
tb
values
(
'b'
, 2,
'b2b2b2b2'
)
insert
into
tb
values
(
'b'
, 4,
'b4b4'
)
insert
into
tb
values
(
'b'
, 5,
'b5b5b5b5b5'
)
go
select
m.
name
,m.val,m.memo
from
(
select
* , px = row_number() over(
order
by
name
, val)
from
tb
) m
where
px = (
select
min
(px)
from
(
select
* , px = row_number() over(
order
by
name
, val)
from
tb
) n
where
n.
name
= m.
name
)
drop
table
tb
/*
name
val memo
---------- ----------- --------------------
a 1 a1
--a的第一个值
b 1 b1
--b的第一个值
(2 行受影响)
*/
|
EXISTS 用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
exists (sql 返回结果集为真)
not
exists (sql 不返回结果集为真)
如下:
表A
ID
NAME
1 A1
2 A2
3 A3
表B
ID AID
NAME
1 1 B1
2 2 B2
3 2 B3
表A和表B是1对多的关系 A.ID => B.AID
SELECT
ID,
NAME
FROM
A
WHERE
EXIST (
SELECT
*
FROM
B
WHERE
A.ID=B.AID)
执行结果为
1 A1
2 A2
原因可以按照如下分析
SELECT
ID,
NAME
FROM
A
WHERE
EXISTS (
SELECT
*
FROM
B
WHERE
B.AID=1)
--->SELECT * FROM B WHERE B.AID=1有值返回真所以有数据
SELECT
ID,
NAME
FROM
A
WHERE
EXISTS (
SELECT
*
FROM
B
WHERE
B.AID=2)
--->SELECT * FROM B WHERE B.AID=2有值返回真所以有数据
SELECT
ID,
NAME
FROM
A
WHERE
EXISTS (
SELECT
*
FROM
B
WHERE
B.AID=3)
--->SELECT * FROM B WHERE B.AID=3无值返回真所以没有数据
NOT
EXISTS 就是反过来
SELECT
ID,
NAME
FROM
A
WHERE
NOT
EXIST (
SELECT
*
FROM
B
WHERE
A.ID=B.AID)
执行结果为
3 A3
===========================================================================
EXISTS =
IN
,意思相同不过语法上有点点区别,好像使用
IN
效率要差点,应该是不会执行索引的原因
SELECT
ID,
NAME
FROM
A
WHERE
ID
IN
(
SELECT
AID
FROM
B)
NOT
EXISTS =
NOT
IN
,意思相同不过语法上有点点区别
SELECT
ID,
NAME
FROM
A
WHERE
ID
NOT
IN
(
SELECT
AID
FROM
B)
下面是普通的用法:
SQL中
IN
,
NOT
IN
,EXISTS,
NOT
EXISTS的用法和差别:
IN
:确定给定的值是否与子查询或列表中的值相匹配。
IN
关键字使您得以选择与列表中的任意一个值匹配的行。
当要获得居住在 California、Indiana 或 Maryland 州的所有作者的姓名和州的列表时,就需要下列查询:
SELECT
ProductID, ProductName
FROM
Northwind.dbo.Products
WHERE
CategoryID = 1
OR
CategoryID = 4
OR
CategoryID = 5
然而,如果使用
IN
,少键入一些字符也可以得到同样的结果:
SELECT
ProductID, ProductName
FROM
Northwind.dbo.Products
WHERE
CategoryID
IN
(1, 4, 5)
IN
关键字之后的项目必须用逗号隔开,并且括在括号中。
下列查询在 titleauthor 表中查找在任一种书中得到的版税少于 50% 的所有作者的 au_id,然后从 authors 表中选择 au_id 与
titleauthor 查询结果匹配的所有作者的姓名:
SELECT
au_lname, au_fname
FROM
authors
WHERE
au_id
IN
(
SELECT
au_id
FROM
titleauthor
WHERE
royaltyper <50)
结果显示有一些作者属于少于 50% 的一类。
NOT
IN
:通过
NOT
IN
关键字引入的子查询也返回一列零值或更多值。
以下查询查找没有出版过商业书籍的出版商的名称。
SELECT
pub_name
FROM
publishers
WHERE
pub_id
NOT
IN
(
SELECT
pub_id
FROM
titles
WHERE
type =
'business'
)
使用 EXISTS 和
NOT
EXISTS 引入的子查询可用于两种集合原理的操作:交集与差集。
两个集合的交集包含同时属于两个原集合的所有元素。
差集包含只属于两个集合中的第一个集合的元素。
EXISTS:指定一个子查询,检测行的存在。
本示例所示查询查找由位于以字母 B 开头的城市中的任一出版商出版的书名:
SELECT
DISTINCT
pub_name
FROM
publishers
WHERE
EXISTS (
SELECT
*
FROM
titles
WHERE
pub_id = publishers.pub_id
AND
type =
'business'
)
SELECT
distinct
pub_name
FROM
publishers
WHERE
pub_id
IN
(
SELECT
pub_id
FROM
titles
WHERE
type =
'business'
)
两者的区别:
EXISTS:后面可以是整句的查询语句如:
SELECT
*
FROM
titles
IN
:后面只能是对单列:
SELECT
pub_id
FROM
titles
NOT
EXISTS:
例如,要查找不出版商业书籍的出版商的名称:
SELECT
pub_name
FROM
publishers
WHERE
NOT
EXISTS (
SELECT
*
FROM
titles
WHERE
pub_id = publishers.pub_id
AND
type =
'business'
)
下面的查询查找已经不销售的书的名称:
SELECT
title
FROM
titles
WHERE
NOT
EXISTS (
SELECT
title_id
FROM
sales
WHERE
title_id = titles.title_id)
语法
EXISTS subquery
参数
subquery:是一个受限的
SELECT
语句 (不允许有 COMPUTE 子句和
INTO
关键字)。有关更多信息,请参见
SELECT
中有关子查询的讨论。
结果类型:Boolean
结果值:如果子查询包含行,则返回
TRUE
。
示例
A. 在子查询中使用
NULL
仍然返回结果集
这个例子在子查询中指定
NULL
,并返回结果集,通过使用 EXISTS 仍取值为
TRUE
。
USE Northwind
GO
SELECT
CategoryName
FROM
Categories
WHERE
EXISTS (
SELECT
NULL
)
ORDER
BY
CategoryName
ASC
GO
B. 比较使用 EXISTS 和
IN
的查询
这个例子比较了两个语义类似的查询。第一个查询使用 EXISTS 而第二个查询使用
IN
。注意两个查询返回相同的信息。
USE pubs
GO
SELECT
DISTINCT
pub_name
FROM
publishers
WHERE
EXISTS
(
SELECT
*
FROM
titles
WHERE
pub_id = publishers.pub_id
AND
type = \'business\')
GO
-- Or, using the IN clause:
USE pubs
GO
SELECT
distinct
pub_name
FROM
publishers
WHERE
pub_id
IN
(
SELECT
pub_id
FROM
titles
WHERE
type = \'business\')
GO
下面是任一查询的结果集:
pub_name
----------------------------------------
Algodata Infosystems
New Moon Books
C.比较使用 EXISTS 和 =
ANY
的查询
本示例显示查找与出版商住在同一城市中的作者的两种查询方法:第一种方法使用 =
ANY
,第二种方法使用 EXISTS。注意这两种方法返回相同的信息。
USE pubs
GO
SELECT
au_lname, au_fname
FROM
authors
WHERE
exists
(
SELECT
*
FROM
publishers
WHERE
authors.city = publishers.city)
GO
-- Or, using = ANY
USE pubs
GO
SELECT
au_lname, au_fname
FROM
authors
WHERE
city =
ANY
(
SELECT
city
FROM
publishers)
GO
D.比较使用 EXISTS 和
IN
的查询
本示例所示查询查找由位于以字母 B 开头的城市中的任一出版商出版的书名:
USE pubs
GO
SELECT
title
FROM
titles
WHERE
EXISTS
(
SELECT
*
FROM
publishers
WHERE
pub_id = titles.pub_id
AND
city
LIKE
\'B%\')
GO
-- Or, using IN:
USE pubs
GO
SELECT
title
FROM
titles
WHERE
pub_id
IN
(
SELECT
pub_id
FROM
publishers
WHERE
city
LIKE
\'B%\')
GO
E. 使用
NOT
EXISTS
NOT
EXISTS 的作用与 EXISTS 正相反。如果子查询没有返回行,则满足
NOT
EXISTS 中的
WHERE
子句。本示例查找不出版商业书籍的出版商的名称:
USE pubs
GO
SELECT
pub_name
FROM
publishers
WHERE
NOT
EXISTS
(
SELECT
*
FROM
titles
WHERE
pub_id = publishers.pub_id
AND
type = \'business\')
ORDER
BY
pub_name
GO
|