MySQL知多少(一)---基础问题及使用总结

  1. 建表时应该总是定义主键,为什么?
    虽然有些数据表结构用不上主键(比如:中间表),但是我们设计表结构的时候还是需要加上主键,因为这样可以便于以后管理和操作数据(比如:加索引、分表等)。
    定义主键的好习惯:

    • 不更新主键列中的值
    • 不重用主键列的值
    • 不在主键列使用会更改的值(例如:用用户名作为主键去标记用户,那如果用户改名的时候,就必须修改主键,并且修改相关的所有数据)
  2. SHOW 相关命令

    • SHOW DATABASES; // 显示所有的数据库
    • SHOW TABLES; // 显示所有表
    • SHOW COLUMNS FROM 表名称; === DESC 表名称; // 查看指定表的表结构
    • SHOW STATUS; // 显示广泛的服务器状态信息
    • SHOW CREATE DADABASE 数据库名称; // 显示指定数据库的创建语句
    • SHOW CREATE TABLE 表名称; // 显示指定数据表的创建语句
    • SHOW GRANTS; // 显示授权用户的安全权限
    • SHOW ERRORS; // 显示错误信息
    • SHOW WARNINGS; // 显示警告信息
    • HELP SHOW; // 显示允许的show语句
  3. 通配符 *
    除非查询时需要检索所有列,否则不要使用通配符 *,虽然使用通配符会让你省事,不用明确列出所需列,但检索不需要的列通常会降低检索和应用程序的性能。

  4. DISTINCT 关键字
    DISTINCT 关键字应用于所有列而不仅是前置它的列。如果给出SELECT DISTINCT vend_id, prod_price,除非指定的两个列都不同,否则所有行都将被检索出来

  5. LIMIT 关键字
    LIMIT 默认从0行开始显示,检索出来的第一行为行0而不是行1。因此,LIMIT 1, 1将检索出第二行而不是第一行
    还有一点需要注意:LIMIT 5,10 的意思是从第6条开始,显示10条记录;而不是有的同学认为的从哪条开始,显示到哪条

  6. 检索出来数据的顺序问题
    检索出的数据并不是以纯粹的随机顺序显示的。如果不排序,数据一般将以它在底层表中出现的顺序显示。这可以是数据最初添加到表中的顺序。但是,如果数据后来进行过更新或删除,则此顺序将会受到MySQL重用回收存储空间的影响。因此,如果不明确控制的话,不应该依赖该排序顺序。因为如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有意义。

  7. 区分大小写和排序顺序在对文本性的数据进行排序时,A与a相同吗?a位于B之前还是位于Z之后?这些问题不是理论问题,其答案取决于数据库如何设置。在字典排序顺序中,A被视为与a相同,这是MySQL(和大多数数据库管理系统)的默认行为。但是,许多数据库管理员能够在需要时改变这种行为(如果你的数据库包含大量外语字符,可能必须这样做)

  8. SQL过滤数据还是应用过滤数据
    数据也可以在应用层过滤。为此目的,SQL的SELECT语句为客户机应用检索出超过实际所需的数据,然后客户机代码对返回数据进行循环,以提取出需要的行。但是,如果在客户机上过滤数据,服务器不得不通过网络发送多余的数据,这将导致网络带宽的浪费。

  9. 空值检查
    在创建表时,表设计人员可以指定其中的列是否可以不包含值。在一个列不包含值时,称其为包含空值NULL。NULL无值,它与字段包含0、空字符串或仅仅包含空格不同。在SELECT 子句中可以通过 IS NULL 和 IS NOT NULL来判断。

  10. 组合WHERE子句
    WHERE可包含任意数目的AND和OR操作符。允许两者结合以进行复杂和高级的过滤。但是其中还需要考虑执行顺序,逻辑运算发具有不同的优先级,具体的次序为非与或;所以任何时候使用具有AND和OR操作符的WHERE子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认计算次序,即使它确实是你想要的东西也是如此。使用圆括号没有什么坏处,它能消除歧义。
    另外还需要考虑的是AND和OR都有短路判断的情况,就是说如果用AND判断两个表达式,当第一个表达式为真时才会去判断第二个表达式,如果第一个表达式为假则直接跳过判断;OR操作也是同样的道理。

  11. IN操作符
    IN操作符完成与OR相同的功能,那么为什么还要使用IN操作符。

    • 在使用长的合法选项清单时,IN操作符的语法更清楚且更直观。
    • 在使用IN时,计算的次序更容易管理(因为使用的操作符更少)
    • IN操作符一般比OR操作符清单执行更快。
    • IN的最大优点是可以包含其他SELECT语句,使得能够更动态地建立WHERE子句
      注意:使用IN操作符的时候,不要同时操作大几千、上万个id, 这样会导致MySQL越过id上的索引,导致全表扫描,最终影响程序性能
  12. NOT操作符
    WHERE子句中的NOT操作符有且只有一个功能,那就是否定它之后所跟的任何条件。NOT对IN、BETWEEN和EXISTS子句取反,这与多数其他DBMS允许使用NOT对各种条件取反有很大的差别。
    为什么使用NOT?对于简单的WHERE子句,使用NOT确实没有什么优势。但在更复杂的子句中,NOT是非常有用的。例如,在与IN操作符联合使用时,NOT使找出与条件列表不匹配的行非常简单。

  13. LIKE操作符
    通配符用来匹配值的一部分的特殊字符(如%、_等结合LIKE操作符)。搜索模式由字面值、通配符或两者组合构成的搜索条件。

    • 最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现任意次数。

    • 下划线(_)通配符
      下划线的用途与%一样,但下划线只匹配单个字符而不是多个字符。

      注意:
      1.通配符可在搜索模式中任意位置使用,并且可以使用多个通配符。
      2.大小写的问题:根据MySQL的配置方式,搜索可以是区分大小写的。如果区分大小写,'test%'与TEST 001将不匹配。
      3.尾空格的问题: 尾空格可能会干扰通配符匹配。
      4.NULL的问题: 虽然似乎%通配符可以匹配任何东西,但有一个例外,即NULL。
      5.通配符很有用。但这种功能是有代价的:通配符搜索的处理一般要比前面讨论的其他搜索所花时间更长。
      6.不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。
      7.在确实需要使用通配符时,除非绝对有必要,否则不要把它们用在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起来是最慢的。
      8.仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。

  14. 正则表达式
    正则表达式是用来匹配文本的特殊的字符串。
    如果你想从一个文本文件中提取电话号码,可以使用正则表达式。
    如果你需要查找名字中间有数字的所有数据,可以使用一个正则表达式。
    如果你想在一个文本块中找到所有重复的单词,可以使用一个正则表达式。
    如果你想替换一个页面中的所有URL为这些URL的实际HTML链接, 也可以使用一个正则表达。

    举个栗子:
    SELECT prodName
    FROM products
    WHERE prodName REGEXP '1000'
    

    为什么要费力地使用正则表达式?在刚才的例子中,正则表达式确实没有带来太多好处(可能还会降低性能,毕竟正则的效率真心不高,能用字符串函数处理的尽量不要用正则),不过,请考虑下面的例子:

    SELECT prod_name 
    FROM products 
    WHERE prod_name REGEXP '.000';
    

    这里使用了正则表达式.000。.是正则表达式语言中一个特殊的字符。它表示匹配任意一个字符,因此,1000、2000、3000等等都会匹配且返回。当然,这个特殊的例子也可以用LIKE和通配符来完成。

    LIKE与REGEXP在LIKE和REGEXP之间有一个重要的差别。请看以下两条语句:

    SELECT prodName
    FROM products
    WHERE prodName LIKE '1000'
    
    SELECT prodName
    FROM products
    WHERE prodName REGEXP '1000'
    

    如果执行上述两条语句,会发现第一条语句不返回数据,而第二条语句返回一行。为什么?
    注意:
    1.LIKE匹配整个列。如果被匹配的文本在列值中出现,LIKE将不会找到它,相应的行也不被返回(除非使用通配符)。而REGEXP在列值内进行匹配,如果被匹配的文本在列值中出现,REGEXP将会找到它,相应的行将被返回。这是一个非常重要的差别。那么,REGEXP能不能用来匹配整个列值(从而起与LIKE相同的作用)?答案是肯定的,使用^和$定位符即可。
    2.正则匹配不区分大小写的问题: MySQL中的正则表达式匹配不区分大小写(即,大写和小写都匹配)。为区分大小写,可使用BINARY关键字,如WHERE prod_name REGEXP BINARY ‘JetPack .000’。
    3.如果要匹配多个值可以给出两个以上的OR条件。例如,'1000 | 2000 | 3000’将匹配1000或2000或3000。

    SELECT prodName
    FROM products
    WHERE prodName REGEXP '1000|2000'
    

    匹配任何单一字符。但是,如果你只想匹配特定的字符,怎么办?可通过指定一组用[和]括起来的字符来完成。

    SELECT prodName
    FROM products
    WHERE prodName REGEXP '[123]000'
    

    正则表达式语言由具有特定含义的特殊字符构成。我们已经看到.、[]、|和-等,还有其他一些字符。请问,如果你需要匹配这些字符,应该怎么办呢?例如,如果要找出包含.字符的值,怎样搜索?为了匹配特殊字符,必须用\为前导。\-表示查找-,\.表示查找.。
    注意:
    为什么要用两个反斜杠‘\’?多数正则表达式实现使用单个反斜杠转义特殊字符,以便能使用这些字符本身。但MySQL要求两个反斜杠(MySQL自己解释一个,正则表达式库解释另一个)。
    正则表达式定位符:^匹配串的开始,$匹配串的结束。 ^有两种用法。在集合中(用[和]定义),用它来否定该集合,否则,用来指串的开始处。
    LIKE和REGEXP的不同在于,LIKE匹配整个串而REGEXP匹配子串。利用定位符,通过用^开始每个表达式,用$结束每个表达式,可以使REGEXP的作用与LIKE一样。

    15.存储在表中的数据都不是应用程序所需要的。我们需要直接从数据库中检索出转换、计算或格式化过的数据;而不是检索出数据,然后再在客户机应用程序或报告程序中重新格式化。我们可在SQL语句内完成的许多转换和格式化工作都可以直接在客户机应用程序内完成。但一般来说,在数据库服务器上完成这些操作比在客户机中完成要快得多,因为DBMS是设计来快速有效地完成这种处理的。

  15. 如何测试计算
    SELECT提供了测试和试验函数与计算的一个很好的办法。虽然SELECT通常用来从表中检索数据,但可以省略FROM子句以便简单地访问和处理表达式。例如,SELECT 3*2;将返回6,SELECT Trim(‘abc’);将返回abc,而SELECT Now()利用Now()函数返回当前日期和时间。通过这些例子,可以明白如何根据需要使用SELECT进行试验。

  16. 函数没有SQL的可移植性强
    能运行在多个系统上的代码称为可移植的。相对来说,多数SQL语句是可移植的,在SQL实现之间有差异时,这些差异通常不那么难处理。而函数的可移植性却不强。几乎每种主要的DBMS的实现都支持其他实现不支持的函数,而且有时差异还很大。 为了代码的可移植,许多SQL程序员不赞成使用特殊实现的功能。虽然这样做很有好处,但不总是利于应用程序的性能。如果不使用这些函数,编写某些应用程序代码会很艰难。必须利用其他方法来实现DBMS非常有效地完成的工作。 如果你决定使用函数,应该保证做好代码注释,以便以后你(或其他人)能确切地知道所编写SQL代码的含义。

  17. 用日期进行过滤需要注意一些别的问题和使用特殊的MySQL函数。首先需要注意的是MySQL使用的日期格式。无论你什么时候指定一个日期,不管是插入或更新表值还是用WHERE子句进行过滤,日期必须为格式yyyy-mm-dd。因此,2005年9月1日,给出为2005-09-01。虽然其他的日期格式可能也行,但这是首选的日期格式,因为它排除了多义性(如,04/05/06是2006年5月4日或2006年4月5日或2004年5月6日或…)
    注意:
    1.应该总是使用4位数字的年份:虽然MySQL支持2位数字的年份,MySQL处理00-69为2000-2069,处理70-99为1970-1999。它们可能是打算要的年份,但使用完整的4位数字年份更可靠,因为MySQL不必做出任何假定。
    2.使用日期作为过滤条件时示例:

    SELECT customer_id, order_num
    FROM orders
    WHERE order_date = '2005-09-01';
    

    使用WHERE order_date = '2005-09-01’可靠吗?
    order_ date的数据类型为datetime。这种类型存储日期及时间值。样例表中的值全都具有时间值00:00:00,但实际中很可能并不总是这样。
    如果用当前日期和时间存储订单日期(因此你不仅知道订单日期,还知道下订单当天的时间),怎么办?
    比如,存储的order_date值为2005-09-01 11:30:05,则WHERE order_date = '2005-09-01’失败。即使给出具有该日期的一行,也不会把它检索出来,因为WHERE匹配失败。
    解决办法是指示MySQL仅将给出的日期与列中的日期部分进行比较,而不是将给出的日期与整个列值进行比较。为此,必须使用Date()函数。
    Date(order_date)指示MySQL仅提取列的日期部分,更可靠的SELECT语句为:

    SELECT customer_id, order_num
    FROM orders
    WHERE DATE(order_date) = '2005-09-01';
    

    如果你想检索出2005年9月下的所有订单,怎么办?简单的相等测试不行,因为它也要匹配月份中的天数。有几种解决办法,其中之一如下所示:

    SELECT customer_id, order_num
    FROM orders
    WHERE DATE(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
    

    还有另外一种办法(一种不需要记住每个月中有多少天或不需要操心闰年2月的办法):

    SELECT customer_id, order_num
    FROM orders
    WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9;
    
  18. GROUP BY
    聚集函数可用来汇总数据。这使我们能够对行进行计数,计算和与平均数,获得最大和最小值而不用检索所有数据。那么再配合 GROUP BY就可以分组汇总数据。
    注意:
    1.GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。
    2.如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)
    3.GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。
    4.如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
    5.使用ROLLUP使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值,例如:

    SELECT vend_id, COUNT(*) as num_prods
    FROM products
    GROUP BY vend_id WITH ROLLUP;
    
  19. HAVING
    HAVING可以配合GROUP BY 使用来过滤分组,规定包括哪些分组,排除哪些分组。
    注意:
    1.HAVING支持所有WHERE操作符,它们的语法是相同的,只是关键字不一样。
    2.HAVING和WHERE的差别:
    WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

  20. SELECT语句中子句的书写顺序

    子 句说 明是否必须使用
    ELECT要返回的列或表达式
    FROM从中检索数据的表仅在从表选择数据时使用
    WHERE行级过滤
    GROUP BY分组说明仅在按组计算聚集时使用
    HAVING分组过滤
    ORDER BY输出排序顺序
    LIMIT要检索的行数
  21. SELECT语句中子句的执行顺序

    	// 所有的字句
    	SELECT 
    	DISTINCT <select_list>
    	FROM <left_table>
    	<join_type> JOIN <right_table>
    	ON <join_condition>
    	WHERE <where_condition>
    	GROUP BY <group_by_list>
    	HAVING <having_condition>
    	ORDER BY <order_by_condition>
    	LIMIT <limit_number>
    	
    	FROM // 首先是from语句找到指定的表
    	JOIN // 联合多表查询返回记录时,并生成一张虚拟表
    	ON // on后面的筛选条件主要是针对的是关联表
    	WHERE // where 筛选符合条件的行
    	GROUP BY // 按照条件吧where过滤后的行,划分成不同分组
    	HAVING // 筛选符合条件的分组
    	SELECT // select查出需要的字段
    	DISTINCT // 再针对select查出的字段的值去重
    	UNION // 合并连个SQL的查询结果(去重后的结果,如果想要全部数据可以使用UNION ALL)
    	ORDER BY // 等所有的数据都查出来、过滤、合并完成后,最后按照指定字段的值进行排序
    	LIMIT // 等对数据的所有操作完成后,按照指定条件限制返回的行数
    
  22. 子查询
    什么是子查询?即嵌套在其他查询中的查询。
    子查询的结果分为四种:

    • 单行单列
    • 单行多列
    • 多行单列
    • 多行多列
      当在select字句中使用子查询时,只能选择单行单列的方式,或者把单行多列、多行单列拼接成一个字段值,才能使用子查询。
      当在from字句中使用子查询时,查询结果作为一个虚拟表,所有情况都可以。
      当在where字句中使用子查询时,可以选择单行单列、单列多行的方式,其他方式则不行
      注意:
      性能问题:
      虽然使用子查询很方便,但它并不是解决这种数据检索的最有效的方法,而且可能因为使用子查询而导致整个SQL查询时间变慢。这时候我们就要寻找优化或者替代方案,使用表连接也基本可以解决使用子查询的问题。所以在工作中可以进行测试,挑选最优方案。
      逐渐增加子查询来建立查询语句
      用子查询测试和调试查询很有技巧性, 特别是在这些语句的复杂性不断增加的情况下更是如此。用子查询建立查询的最可靠的方法是逐渐进行,首先,建立和测试最内层的查询。然后,用硬编码数据建立和测试外层查询,并且仅在确认它正常后才嵌入子查询。这时,再次测试它。对于要增加的每个查询,重复这些步骤。这样做仅给构造查询增加了一点点时间,但节省了以后(找出查询为什么不正常)的大量时间,并且极大地提高了查询一开始就正常工作的可能性。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值