手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表分类:DataBase

增加MYSQL的插入值的容错性

众所周知,我们在插入数据库的时候,都是:insert into table (xxx) values('0');这种方式。
嗯,如果xxx是char或者varchar,并不会出错,但如果xxx是int型或者日期型,则可能会出错,也可能不出错,这是由您的配置决定的。
您可以看这里:
1.修改my.ini

XML/HTML代码
  1. ctrl+f 查找 sql-mode  
  2.   
  3. 将它值改为 "ANSI"  
  4. sql-mode="ANSI";  
  5. 重启数据库,就ok了.  

2.动态修改数据库模式

XML/HTML代码
  1. 在启动数据库后,使用sql语句 SET sql_mode='ansi' ,   

就ok了

--------------------------------------------------
第2个方法没用过.... T.T
手册地址在这.
http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/database-administration.html#server-sql-mode
sql-mode 是服务器模式
值的不同,mysql处理sql语句的方式也不同.

当值为ansi时,
mysql将更改sql语句的语法和行为,使其更符合标准SQL。
说白了,就是会修改错误.容错性高.

这样你给datetime项 和 int项 插入 空字符串,
mysql会将datetime的空字符改为 0000-00-00 00:00,
将int的空字符串改为0 .
其他值的作用.自己看手册.
-------上面这一段内容来自:http://ymx.iteye.com/blog/829046
是因为fireguns在询问的时候才想起要查这玩意,所以我就问了一下google

然后,firegus找到的资料是:

XML/HTML代码
  1. # Set the SQL mode to strict  
  2. sql-mode=”STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION”  
  3.   
  4. 改为:  
  5.   
  6. # Set the SQL mode to strict  
  7. sql-mode=”NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION”  

手册上说的SQLMODE是指:

XML/HTML代码
  1. 5.3.2. SQL服务器模式  
  2.   
  3. MySQL服务器可以以不同的SQL模式来操作,并且可以为不同客户端应用不同模式。这样每个应用程序可以根据自己的需求来定制服务器的操作模式。  
  4.   
  5. 模式定义MySQL应支持哪些SQL语法,以及应执行哪种数据验证检查。这样可以更容易地在不同的环境中使用MySQL,并结合其它数据库服务器使用MySQL。  
  6.   
  7. 你可以用--sql-mode="modes"选项启动mysqld来设置默认SQL模式。如果你想要重设,该值还可以为空(--sql-mode ="")。  
  8.   
  9. 你还可以在启动后用SET [SESSION|GLOBAL] sql_mode='modes'语句设置sql_mode变量来更改SQL模式。设置 GLOBAL变量时需要拥有SUPER权限,并且会影响从那时起连接的所有客户端的操作。设置SESSION变量只影响当前的客户端。任何客户端可以随时更改自己的会话 sql_mode值。  
  10.   
  11. Modesis是用逗号(‘,’)间隔开的一系列不同的模式。你可以用SELECT @@sql_mode语句查询当前的模式。默认值是空(没有设置任何模式)。  
  12.   
  13. 主要重要sql_mode值为:  
  14.   
  15. ·         ANSI  
  16.   
  17. 更改语法和行为,使其更符合标准SQL。  
  18.   
  19. ·         STRICT_TRANS_TABLES  
  20.   
  21. 如果不能将给定的值插入到事务表中,则放弃该语句。对于非事务表,如果值出现在单行语句或多行语句的第1行,则放弃该语句。本节后面给出了更详细的描述。  
  22.   
  23. ·         TRADITIONAL  
  24.   
  25. Make MySQL的行为象“传统”SQL数据库系统。该模式的简单描述是当在列中插入不正确的值时“给出错误而不是警告”。注释:一旦发现错误立即放弃INSERT/UPDATE。如果你使用非事务存储引擎,这种方式不是你想要的,因为出现错误前进行的数据更改不会“滚动”,结果是更新“只进行了一部分”。  
  26.   
  27. 本手册指“严格模式”,表示至少STRICT _TRANS_TABLES或STRICT _ALL_TABLES被启用的模式。  
  28.   
  29. 下面描述了支持的所有模式:  
  30.   
  31. ·         ALLOW_INVALID_DATES  
  32.   
  33. 在严格模式下不要检查全部日期。只检查1到12之间的月份和1到31之间的日。这在Web应用程序中,当你从三个不同的字段获取年、月、日,并且想要确切保存用户插入的内容(不进行日期验证)时很重要。该模式适用于DATE和DATETIME列。不适合TIMESTAMP列,TIMESTAMP列需要验证日期。  
  34.   
  35. 启用严格模式后,服务器需要合法的月和日,不仅仅是分别在1到12和1到31范围内。例如,禁用严格模式时'2004-04-31'是合法的,但启用严格模式后是非法的。要想在严格模式允许遮掩固定日期,还应启用ALLOW_INVALID_DATES。  
  36.   
  37. ·         ANSI_QUOTES  
  38.   
  39. 将‘"’视为识别符引号(‘`’引号字符),不要视为字符串的引号字符。在ANSI模式,你可以仍然使用‘`’来引用识别符。启用ANSI_QUOTES后,你不能用双引号来引用字符串,因为它被解释为识别符。  
  40.   
  41. ·         ERROR_FOR_DIVISION_BY_ZERO  
  42.   
  43. 在严格模式,在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作结果为NULL。  
  44.   
  45. ·         HIGH_NOT_PRECEDENCE  
  46.   
  47. NOT操作符的优先顺序是表达式例如NOT a BETWEEN b AND c被解释为NOT (a BETWEEN b AND c)。在一些旧版本MySQL中, 表达式被解释为(NOT a) BETWEEN b AND c。启用HIGH_NOT_PRECEDENCESQL模式,可以获得以前的更高优先级的结果。  
  48.   
  49. mysql> SET sql_mode = '';  
  50.   
  51. mysql> SELECT NOT 1 BETWEEN -5 AND 5;  
  52.   
  53.         -> 0  
  54.   
  55. mysql> SET sql_mode = 'broken_not';  
  56.   
  57. mysql> SELECT NOT 1 BETWEEN -5 AND 5;  
  58.   
  59.         -> 1  
  60.   
  61. ·         IGNORE_SPACE  
  62.   
  63. 允许函数名和‘(’之间有空格。强制将所有函数名视为保存的字。结果是,如果你想要访问保存为字的数据库、表或列名,你必须引用它。例如,因为有USER()函数,mysql数据库中的user表名和该表内的User列被保存下来,因此你必须引用它们:  
  64.   
  65. SELECT "User" FROM mysql."user";  
  66.   
  67. ·         NO_AUTO_CREATE_USER  
  68.   
  69. 防止GRANT自动创建新用户,除非还指定了密码。  
  70.   
  71. ·         NO_AUTO_VALUE_ON_ZERO  
  72.   
  73. NO_AUTO_VALUE_ON_ZERO影响AUTO_INCREMENT列的处理。一般情况,你可以向该列插入NULL或0生成下一个序列号。NO_AUTO_VALUE_ON_ZERO禁用0,因此只有NULL可以生成下一个序列号。  
  74.   
  75. 如果将0保存到表的AUTO_INCREMENT列,该模式会很有用。(不推荐采用该惯例)。例如,如果你用mysqldump转储表并重载,MySQL遇到0值一般会生成新的序列号,生成的表的内容与转储的表不同。重载转储文件前启用NO_AUTO_VALUE_ON_ZERO可以解决该问题。mysqldump在输出中自动包括启用NO_AUTO_VALUE_ON_ZERO的语句。  
  76.   
  77. ·         NO_BACKSLASH_ESCAPES  
  78.   
  79. 禁用反斜线字符(‘\’)做为字符串内的退出字符。启用该模式,反斜线则成为普通字符。  
  80.   
  81. ·         NO_DIR_IN_CREATE  
  82.   
  83. 创建表时,忽视所有INDEX DIRECTORY和DATA DIRECTORY指令。该选项对从复制服务器有用。  
  84.   
  85. ·         NO_ENGINE_SUBSTITUTION  
  86.   
  87. 如果需要的存储引擎被禁用或未编译,可以防止自动替换存储引擎。  
  88.   
  89. ·         NO_FIELD_OPTIONS  
  90.   
  91. 不要在SHOW CREATE TABLE的输出中打印MySQL专用列选项。该模式在可移植模式(portability mode)下用于mysqldump。  
  92.   
  93. ·         NO_KEY_OPTIONS  
  94.   
  95. 不要在SHOW CREATE TABLE的输出中打印MySQL专用索引选项。该模式在可移植模式(portability mode)下用于mysqldump。  
  96.   
  97. ·         NO_TABLE_OPTIONS  
  98.   
  99. 不要在SHOW CREATE TABLE的输出中打印MySQL专用表选项(例如ENGINE)。该模式在可移植模式(portability mode)下用于mysqldump。  
  100.   
  101. ·         NO_UNSIGNED_SUBTRACTION  
  102.   
  103. 在减运算中,如果某个操作数没有符号,不要将结果标记为UNSIGNED。请注意这样使UNSIGNED BIGINT不能100%用于上下文中。参见12.8节,“Cast函数和操作符”。  
  104.   
  105.    
  106.   
  107. ·         NO_ZERO_DATE  
  108.   
  109. 在严格模式,不要将 '0000-00-00'做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告。  
  110.   
  111. ·         NO_ZERO_IN_DATE  
  112.   
  113. 在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告。  
  114.   
  115. ·         ONLY_FULL_GROUP_BY  
  116.   
  117. 不要让GROUP BY部分中的查询指向未选择的列。  
  118.   
  119. ·         PIPES_AS_CONCAT  
  120.   
  121. 将||视为字符串连接操作符(+)(同CONCAT()),而不视为OR。  
  122.   
  123. ·         REAL_AS_FLOAT  
  124.   
  125. 将REAL视为FLOAT的同义词,而不是DOUBLE的同义词。  
  126.   
  127. ·         STRICT_TRANS_TABLES  
  128.   
  129. 为所有存储引擎启用严格模式。非法数据值被拒绝。后面有详细说明。  
  130.   
  131. ·         STRICT_TRANS_TABLES  
  132.   
  133. 为事务存储引擎启用严格模式,也可能为非事务存储引擎启用严格模式。后面有详细说明。  
  134.   
  135. 严格模式控制MySQL如何处理非法或丢失的输入值。有几种原因可以使一个值为非法。例如,数据类型错误,不适合列,或超出范围。当新插入的行不包含某列的没有显示定义DEFAULT子句的值,则该值被丢失。  
  136.   
  137. 对于事务表,当启用STRICT_ALL_TABLES或STRICT_TRANS_TABLES模式时,如果语句中有非法或丢失值,则会出现错误。语句被放弃并滚动。  
  138.   
  139. 对于非事务表,如果插入或更新的第1行出现坏值,两种模式的行为相同。语句被放弃,表保持不变。如果语句插入或修改多行,并且坏值出现在第2或后面的行,结果取决于启用了哪个严格选项:  
  140.   
  141. ·         对于STRICT_ALL_TABLES,MySQL返回错误并忽视剩余的行。但是,在这种情况下,前面的行已经被插入或更新。这说明你可以部分更新,这可能不是你想要的。要避免这点,最好使用单行语句,因为这样可以不更改表即可以放弃。  
  142.   
  143. ·         对于STRICT_TRANS_TABLES,MySQL将非法值转换为最接近该列的合法值并插入调整后的值。如果值丢失,MySQL在列中插入隐式 默认值。在任何情况下,MySQL都会生成警告而不是给出错误并继续执行语句。13.1.5节,“CREATE TABLE语法”描述了隐式默认值。  
  144.   
  145. 严格模式不允许非法日期,例如'2004-04-31'。它不允许禁止日期使用“零”部分,例如'2004-04-00'或“零”日期。要想禁止,应在严格模式基础上,启用NO_ZERO_IN_DATE和NO_ZERO_DATE SQL模式。  
  146.   
  147. 如果你不使用严格模式(即不启用STRICT_TRANS_TABLES或STRICT_ALL_TABLES模式),对于非法或丢失的值,MySQL将插入调整后的值并给出警告。在严格模式,你可以通过INSERT IGNORE或UPDATE IGNORE来实现。参见13.5.4.22节,“SHOW WARNINGS语法”。  
  148.   
  149. 下面的特殊模式快速组合了前面所列的模式。  
  150.   
  151. 其中包括大多数最新版本MySQL中的所有模式值。旧版本中,组合模式不包括新版本中没有的不适用的具体模式值。  
  152.   
  153. ·         ANSI  
  154.   
  155. 等同REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE。参见1.8.3节,“在ANSI模式下运行MySQL”。  
  156.   
  157. ·         DB2  
  158.   
  159. 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS。  
  160.   
  161. ·         MAXDB  
  162.   
  163. 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、 NO_AUTO_CREATE_USER。  
  164.   
  165. ·         MSSQL  
  166.   
  167. 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、 NO_FIELD_OPTIONS。  
  168.   
  169. ·         MYSQL323  
  170.   
  171. 等同NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE。  
  172.   
  173. ·         MYSQL40  
  174.   
  175. 等同NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE。  
  176.   
  177. ·         ORACLE  
  178.   
  179. 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER。  
  180.   
  181. ·         POSTGRESQL  
  182.   
  183. 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS。  
  184.   
  185. ·         TRADITIONAL  
  186.   
  187. 等同STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER。  

Tags: mysql, insert, int, datetime

/*!select*/ 突破防注入

看到本文的时候,其实我还是很蛋定的,大约早在3年多前就看到有人这么做过了,当时还给我发了一大堆这样的代码。
其实还有例子,那就是当初在liba网的时候,有一段时间突然发现MYSQL超慢。bobby查询了所有的数据库查询,发现了类似本文的例子,那时候其实很惊讶,/*!xxxx*/这样的代码不是被注释了吗?又能用来干嘛 ?
所以,今天看到这一篇博客的时候,还是忍不住贴出来,因为这已经真的不算是秘密的秘密了。

来源:http://hi.baidu.com/isbx/blog/item/795dcc112b85f40eb8127b4d.html

作者:meao

昨天在检测一个外国PHP网站时
在id=255后加’出现forbidden
于是我and 1=1正常 and 1=2出错
说明肯定有注入
接着我order by猜出字段
然后union select 1,2,3,4 //悲剧的又出现了forbidden
肯定是做了过滤了
后来构造了语句id=-255+union+/*!select*/+1,2,3,4

原理:

MySQL Server supports some variants of C-style comments. These enable you to write code that includes MySQL extensions, but is still portable, by using comments of the following form:

/*! MySQL-specific code */

In this case, MySQL Server parses and executes the code within the comment as it would any other SQL statement, but other SQL servers will ignore the extensions. For example, MySQL Server recognizes the STRAIGHT_JOIN keyword in the following statement, but other servers will not:

SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE …

If you add a version number after the “!” character, the syntax within the comment is executed only if the MySQL version is greater than or equal to the specified version number. The TEMPORARY keyword in the following comment is executed only by servers from MySQL 3.23.02 or higher:

CREATE /*!32302 TEMPORARY */ TABLE t (a INT);

The comment syntax just described applies to how the mysqld server parses SQL statements. The mysql client program also performs some parsing of statements before sending them to the server. (It does this to determine statement boundaries within a multiple-statement input line.)

Tags: select, mysql

转:mysql语句最大长度

我自己没注意过,但有人遇到了,就找找这方面的资料。
所以,纯转,有问题不要找我,http://bbs.zaopai.com/read-htm-tid-386.html:

max_allowed_packet用来限制mysql客户端和服务器通信数据包的长度的,mysql的默认限制1M。

所以,WIN32的,    请在你的系统目录下查找my.ini  
    
在Linux下你查找my.cnf

在里面加入
set-variable = max_allowed_packet=6M
set-variable = net_buffer_length=4K

=========================

mysql有一个max_allowed_packet变量,可以控制其通信缓冲区的最大长度。要想为mysql将max_allowed_packet变量的值设置为16MB,使用下面的任何一个命令:

shell> mysql --max_allowed_packet=16777216shell> mysql --max_allowed_packet=16M第1个命令以字节指定值。第2个命令以兆字节指定值。变量值可以有一个后缀K、M或者G(可以为大写或 小写)来表示千字节、兆字节或者十亿字节的单位。

在选项文件中,变量设定值没有引导破折号:

[mysql]max_allowed_packet=16777216或:

[mysql]max_allowed_packet=16M

注:max_allowed_packet参数是在mysql4以后才有的,在mysql4以前版本,还没有这个参数

Tags: mysql

常用SQL整理

  说明:复制表(只复制结构,源表名:a 新表名:b)
      SQL: select * into b from a where 1<>1  (mysql无法执行

  说明:拷贝表(拷贝数据,源表名:a 目标表名:b)

  SQL: insert into b(a, b, c) select d,e,f from b;

  说明:显示文章、提交人和最后回复时间[这个还是用innerJOIN较好]

  SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

  说明:外连接查询(表名1:a 表名2:b)[MYSQL已经支持using函数]

  SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

  说明:日程安排提前五分钟提醒[MYSQL无getdate函数]

  SQL: select * from 日程安排 where datediff('minute',开始时间,getdate())>5

  说明:两张关联表,删除主表中已经在副表中没有的信息

  SQL:

  delete from info where not exists ( select * from infobz where info.infid=infobz.infid )

  说明:看看即可,不要深究

  SQL:

  SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE

  FROM TABLE1,

  (SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE

  FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND

  FROM TABLE2

  WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X,

  (SELECT NUM, UPD_DATE, STOCK_ONHAND

  FROM TABLE2

  WHERE TO_CHAR(UPD_DATE,'YYYY/MM') =

  TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') ¦¦ '/01','YYYY/MM/DD') - 1, 'YYYY/MM') ) Y,

  WHERE X.NUM = Y.NUM (+)

  AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND ) B

  WHERE A.NUM = B.NUM

  说明:--

  SQL:

   select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系名称='"&strdepartmentname&"' and 专业名称='"&strprofessionname&"' order by 性别,生源地,高考总成绩

  说明:   从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源)

  SQL:

  SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,

  SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC

  FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration

  FROM TELFEESTAND a, TELFEE b

  WHERE a.tel = b.telfax) a

  GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')

  说明:四表联查问题:

  SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

  说明:得到表中最小的未使用的ID号

  SQL:

  SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID

  FROM Handle

  WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)

原文来自:精妙SQL语句精华

Tags: sqlserver

一句SQL:取得相同sortid的结果集,每种 ID三条数据

一个表:

SQL代码
  1. CREATE TABLE `book` (   
  2.   `bookid` int(11) unsigned NOT NULL AUTO_INCREMENT,  
  3.   `sortid` int(11) NOT NULL,  
  4.   `bookname` varchar(255) NOT NULL DEFAULT '',  
  5.   PRIMARY KEY (`bookid`)  
  6. ) ENGINE=InnoDB AUTO_INCREMENT=80729 DEFAULT CHARSET=utf8;  

数据是这样的:

XML/HTML代码
  1. insert  into `book`(`bookid`,`sortid`,`bookname`) values (1,1,'1'),(2,1,'2'),(3,1,'3'),(4,1,'4'),(5,2,'1'),(6,2,'2'),(7,2,'3'),(8,2,'4'),(9,2,'5'),(10,2,'6'),(11,2,'7'),(12,2,'8'),(13,2,'9'),(14,2,'10'),(15,2,'11'),(16,3,'1'),(17,3,'2'),(18,3,'3'),(19,3,'4'),(20,3,'5'),(21,3,'6'),(22,3,'7'),(23,3,'8'),(24,3,'9'),(25,3,'10'),(26,3,'11'),(27,3,'12'),(28,4,'1'),(29,4,'2'),(30,4,'3'),(31,4,'4'),(32,4,'5'),(33,5,'1'),(34,5,'2'),(35,5,'3'),(36,5,'4');  

在这种情况下,要取得 sortid IN (1,2,3)的数据,每个sortid的结果是3条。
这种题目网上很多,但真的没有一种特别好SQL,在网上有很多种。最初的时候,我自己是想着用union来处理,但最终这种方法太伤了,同事clear提出的SQL不错,试了一下,在几万条数据的时候,效率还可以,而且SQL相对简单:

SQL代码
  1. SELECT sortid,bookname FROM book b WHERE sortid IN(1,2) AND 3>(SELECT COUNT(1) FROM book WHERE b.sortid=sortid AND bookid<b.bookid)   

表自关联,在sortid上建索引,效率还不错。