Archive for the ‘mysql’ Category

mysql主从(master-slave)复制安装配置

Posted by 机器人 on 6th 一月 2010 in mysql

一. 环境准备

准备两台服务器,IP分别为
192.168.1.119 (主数据库服务器)
192.168.1.120 (从数据库服务器)

分别装好mysql数据库服务器
Read the rest of this entry »

mysql表快速制造测试数据

Posted by 机器人 on 10th 十二月 2009 in mysql

帖子表只有20多W的数据,快添加测试数据至400W
执行以下语句。

INSERT INTO posts(
	bar_id,thread_id,first,author,authorid,
	subject,dateline,message,useip,haveattach
	) 
SELECT 
	bar_id,thread_id,first,author,authorid,
	subject,dateline,message,useip,haveattach 
FROM posts;

Read the rest of this entry »

mysql随机数函数(rand())

Posted by 机器人 on 15th 八月 2008 in mysql

生成3,6之间的随机整数

FLOOR(3 + (RAND() * 6))

在4后面添加一个3到6之间的整数

CONCAT(343,FLOOR(3 + (RAND() * 6)))

在某一字段后面添加一位3,6之间的整数

UPDATE test SET xx= CONCAT(xx,FLOOR(3 +(RAND() * 6)));
Read the rest of this entry »

MySQL 5.0 新特性教程 存储过程(整理)

Posted by 机器人 on 9th 十一月 2007 in mysql

MySQL 5.0 新特性教程 存储过程

Variables 变量

在复合语句中声明变量的指令是DECLARE。

(1) Example with two DECLARE statements

两个DECLARE语句的例子

CREATE PROCEDURE p8 ()
BEGIN
    DECLARE a INT;
    DECLARE b INT;
    SET a = 5;
    SET b = 5;
    INSERT INTO t VALUES (a);
    SELECT s1 * a FROM t WHERE s1 >= b;
END; // /* I won't CALL this */

在过程中定义的变量并不是真正的定义,你只是在BEGIN/END块内定义了而已(译注:也就是形参)。

注意这些变量和会话变量不一样,不能使用修饰符@你必须清楚的在BEGIN/END块中声明变量和它们的类型。

变量一旦声明,你就能在任何能使用会话变量、文字、列名的地方使用。

  (2) Example with no DEFAULT clause and SET statement

  没有默认子句和设定语句的例子

CREATE PROCEDURE p9 ()
BEGIN
    DECLARE a INT /* there is no DEFAULT clause */;
    DECLARE b INT /* there is no DEFAULT clause */;
    SET a = 5; /* there is a SET statement */
    SET b = 5; /* there is a SET statement */
    INSERT INTO t VALUES (a);
    SELECT s1 * a FROM t WHERE s1 >= b;
END; // /* I won't CALL this */

 

有很多初始化变量的方法。如果没有默认的子句,那么变量的初始值为NULL。你可以在任何时候使用SET语句给变量赋值。

  (3) Example with DEFAULT clause

  含有DEFAULT子句的例子

CREATE PROCEDURE p10 ()
BEGIN
    DECLARE a, b INT DEFAULT 5;
    INSERT INTO t VALUES (a);
    SELECT s1 * a FROM t WHERE s1 >= b;
END; //

我们在这里做了一些改变,但是结果还是一样的。在这里使用了DEFAULT子句来设定初始值,这就不需要把DECLARE和SET语句的实现分开了。

  (4) Example of CALL

  调用的例子

mysql> CALL p10() //
+--------+ 
| s1 * a |
+--------+ 
| 25 |
| 25 |
+--------+ 
2 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

  结果显示了过程能正常工作

  (5) Scope

作用域

mysql> CALL p11()//
+-------+ 
| x1 |
+-------+ 
| inner |
+-------+ 
+-------+ 
| x1 |
+-------+ 
| outer |
+-------+ 

现在我们来讨论一下作用域的问题。例子中有嵌套的BEGIN/END块,当然这是合法的。同时包含两个变量,名字都是x1,这样也是合法的。内部的变量在其作用域内享有更高的优先权。

当执行到END语句时,内部变量消失,此时已经在其作用域外,变量不再可见了,因此在存储过程外再也不能找到这个声明了的变量,但是你可以通过OUT参数或者将其值指派 给会话变量来保存其值。

  调用作用域例子的过程: 

mysql> CALL p11()//
+-------+ 
| x1 |
+-------+ 
| inner |
+-------+ 
+-------+ 
| x1 |
+-------+ 
| outer |
+-------+ 

  我们看到的结果时第一个SELECT语句检索到最内层的变量,第二个检索到第二层的变量

Conditions and IF-THEN-ELSE 条件式和IF-THEN-ELSE

  1.

  现在我们可以写一些包含条件式的例子:

CREATE PROCEDURE p12 (IN parameter1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = parameter1 + 1;
    IF variable1 = 0 THEN
        INSERT INTO t VALUES (17);
    END IF;
    IF parameter1 = 0 THEN
        UPDATE t SET s1 = s1 + 1;
    ELSE
        UPDATE t SET s1 = s1 + 2;
    END IF;
END; //

  这里是一个包含IF语句的过程。里面有两个IF语句,一个是IF语句END IF,另一个是IF语句ELSE语句END IF。我们可以在这里使用复杂的过程,但我会尽量使其简单让你能更容易弄清楚。

  2. 

CALL p12 (0) //

  我们调用这个过程,传入值为0,这样parameter1的值将为0。

  3.

CREATE PROCEDURE p12 (IN parameter1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = parameter1 + 1; <-- 
    IF variable1 = 0 THEN
        INSERT INTO t VALUES (17);
    END IF;
    IF parameter1 = 0 THEN
        UPDATE t SET s1 = s1 + 1;
    ELSE
        UPDATE t SET s1 = s1 + 2;
    END IF;
END; //

  这里变量variable1被赋值为parameter1加1的值,所以执行后变量variable1为1。

  4.

CREATE PROCEDURE p12 (IN parameter1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = parameter1 + 1;
    IF variable1 = 0 THEN <-- 
        INSERT INTO t VALUES (17);
    END IF;
    IF parameter1 = 0 THEN
        UPDATE t SET s1 = s1 + 1;
    ELSE
        UPDATE t SET s1 = s1 + 2;
    END IF;
END; //

因为变量variable1值为1,因此条件"if variable1 = 0"为假,

IF

……

END IF

  被跳过,没有被执行。

  5.

  到第二个IF条件,判断结果为真,于是中间语句被执行了

  6.

CREATE PROCEDURE p12 (IN parameter1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = parameter1 + 1;
    IF variable1 = 0 THEN
        INSERT INTO t VALUES (17);
    END IF;
    IF parameter1 = 0 THEN
        UPDATE t SET s1 = s1 + 1; <-- 
    ELSE
        UPDATE t SET s1 = s1 + 2;
    END IF;
END; //

因为参数parameter1值等于0,UPDATE语句被执行。如果parameter1值为NULL,则下一条UPDATE语句将被执行现在表t中有两行,他们都包含值5,所以如果我们调用p12,两行的值会变成6。

  7.

mysql> CALL p12(0)//
Query OK, 2 rows affected (0.28 sec)
mysql> SELECT * FROM t//
+------+ 
| s1 |
+------+ 
| 6 |
| 6 |
+------+ 
2 rows in set (0.01 sec)

  结果也是我们所期望的那样。

CASE 指令

  1.

CREATE PROCEDURE p13 (IN parameter1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = parameter1 + 1;
    CASE variable1
    WHEN 0 THEN INSERT INTO t VALUES (17);
    WHEN 1 THEN INSERT INTO t VALUES (18);
    ELSE INSERT INTO t VALUES (19);
    END CASE;
END; //

  如果需要进行更多条件真假的判断我们可以使用CASE语句。CASE语句使用和IF一样简单。

  我们可以参考上面的例子:

 2.

mysql> select * from t; //
+------+ 
| s1 |
+------+ 
....
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+------+ 
9 rows in set (0.00 sec)

  执行过程后,传入值1,如上面例子,值19被插入到表t中。

  Question

  问题

  问题: CALL p13(NULL) //的作用是什么?

  另一个:这个CALL语句做了那些动作?

  你可以通过执行后观察SELECT做了什么,也可以根据代码判断,在5秒内做出。

  Answer

  答案

mysql> CALL p13(NULL)//
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM t//
+------+ 
| s1 |
+------+ 
| 6 |
| 6 |
| 19 |
| 19 |
+------+ 
4 rows in set (0.00 sec)

  答案是当你调用p13时,MySQL插入了另一条包含数值19的记录。原因是变量variable1的值为NULL,CASE语句的ELSE部分就被执行了。希望这对大家有意义。如果你回答不出来,没有问题,我们可以继续向下走。

Loops 循环语句

WHILE … END WHILE

LOOP … END LOOP

REPEAT … END REPEAT

GOTO

  下面我们将会创建一些循环。我们有三种标准的循环方式:

  WHILE循环,LOOP循环以及REPEAT循环。还有一种非标准的循环方式:GO TO(译者语:最好不要用吧,用了就使流程混乱)。

WHILE ... END WHILE
CREATE PROCEDURE p14 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    WHILE v < 5 DO
        INSERT INTO t VALUES (v);
        SET v = v + 1;
    END WHILE;
END; //

  这是WHILE循环的方式。我很喜欢这种方式,它跟IF语句相似,因此不需要掌握很多新的语法。这里的INSERT和SET语句在WHILE和END WHILE之间,当变量v大于5的时候循环将会退出。使用

"SET v = 0;"

  语句使为了防止一个常见的错误,如果没有初始化,默认变量值为NULL,而NULL和任何值操作结果都为NULL。

WHILE … END WHILE example

mysql> CALL p14()// 

Query OK, 1 row affected (0.00 sec)

  以上就是调用过程p14的结果不用关注系统返回是"one row affected"还是"five rows affected",因为这里的计数只对最后一个INSERT动作进行计数。

WHILE … END WHILE example: CALL

mysql> select * from t; //
+------+ 
| s1 |
+------+ 
....
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+------+ 
9 rows in set (0.00 sec)

  调用后可以看到程序向数据库中插入了5行。

REPEAT … END REPEAT

CREATE PROCEDURE p15 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    REPEAT
        INSERT INTO t VALUES (v);
        SET v = v + 1;
        UNTIL v >= 5
    END REPEAT;
END; //

这是一个REPEAT循环的例子,功能和前面WHILE循环一样。区别在于它在执行后检查结果,而WHILE则是执行前检查。(译者语:可能等同于DO WHILE吧)

REPEAT … END REPEAT: look at the UNTIL: UNTIL的作用

  注意到UNTIL语句后面没有分号,在这里可以不写分号,当然你加上额外的分号更好。

  REPEAT … END REPEAT: calling :调用

mysql> CALL p15()//
Query OK, 1 row affected (0.00 sec)
mysql> SELECT COUNT(*) FROM t//
+----------+ 
| COUNT(*) |
+----------+ 
| 14 |
+----------+ 
1 row in set (0.00 sec)

  我们可以看到调用p15过程后又插入了5行记录

LOOP … END LOOP

CREATE PROCEDURE p16 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
    END LOOP;
END; //

  以上是LOOP循环的例子。

LOOP循环不需要初始条件,这点和WHILE循环相似,同时它又和REPEAT循环一样也不需要结束条件。

  LOOP … END LOOP: with IF and LEAVE 包含IF和LEAVE的LOOP循环

CREATE PROCEDURE p16 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
        INSERT INTO t VALUES (v);
        SET v = v + 1;
        IF v >= 5 THEN <-- 
            LEAVE loop_label;
        END IF;
    END LOOP;
END; //

  在循环内部加入IF语句,在IF语句中包含LEAVE语句。这里LEAVE语句的意义是离开循环。

  LEAVE的语法是LEAVE加循环语句标号,关于循环语句的标号问题我会在后面进一步讲解。

  LOOP … END LOOP: calling :调用

mysql> CALL p16()//
Query OK, 1 row affected (0.00 sec)
mysql> SELECT COUNT(*) FROM t//
+----------+ 
| COUNT(*) |
+----------+ 
| 19 |
+----------+ 
1 row in set (0.00 sec)

  调用过程p16后,结果是另5行被插入表t中。

abels 标号

CREATE PROCEDURE p17 ()
label_1: BEGIN
label_2: WHILE 0 = 1 DO LEAVE label_2; END
WHILE;
label_3: REPEAT LEAVE label_3; UNTIL 0 =0
END REPEAT;
label_4: LOOP LEAVE label_4; END LOOP;
END; //

  最后一个循环例子中我使用了语句标号。现在这里有一个包含4个语句标号的过程的例子。我们可以在BEGIN、WHILE、REPEAT或者LOOP语句前使用语句标号,语句标号只能在合法的语句前面使用。因此"LEAVE label_3"意味着离开语句标号名定义为label_3的语句或复合语句。

End Labels 标号结束符 

CREATE PROCEDURE p18 ()
label_1: BEGIN
label_2: WHILE 0 = 1 DO LEAVE label_2; END
WHILE label_2;
label_3: REPEAT LEAVE label_3; UNTIL 0 =0
END REPEAT label_3 ;
label_4: LOOP LEAVE label_4; END LOOP
label_4 ;
END label_1 ; //

  你也可以在语句结束时使用语句标号,和在开头时使用一样。这些标号结束符并不是十分有用。

  它们是可选的。如果你需要,他们必须和开始定义的标号名字一样当然为了有良好的编程习惯,方便他人阅读,最好还是使用标号结束符。

LEAVE and Labels 跳出和标号

CREATE PROCEDURE p19 (parameter1 CHAR)
label_1: BEGIN
    label_2: BEGIN
        label_3: BEGIN
            IF parameter1 IS NOT NULL THEN
                IF parameter1 = 'a' THEN
                    LEAVE label_1;
                    ELSE BEGIN
                        IF parameter1 = 'b' THEN
                            LEAVE label_2;
                            ELSE
                            LEAVE label_3;
                        END IF;
                    END;
                END IF;
            END IF;
        END;
    END;
END;//
LEAVE

  语句使程序跳出复杂的复合语句。

ITERATE

  迭代如果目标是ITERATE(迭代)语句的话,就必须用到LEAVE语句

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
END LOOP;

  (迭代)语句和LEAVE语句一样也是在循环内部的循环引用,它有点像C语言中的“Continue”,同样它可以出现在复合语句中,引用复合语句标号,ITERATE(迭代)意思是重新开始复合语句。

  那我们启动并观察下面这个循环,这是个需要迭代过程的循环:

ITERATE: Walking through the loop

深入循环

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP <-- 
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
END LOOP; 

END; //

  让这个已经定义了标号的循环运行起来。

ITERATE: Walking through the loop

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    IF v = 3 THEN <-- 
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
    END LOOP;
END; //

v的值变成3,然后我们把它增加到4。

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label; <-- 
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
    END LOOP;
END; //

ITERATE: walking through the loop

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP <-- 
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
    END LOOP;
END; //

  然后开始ITERATE(迭代)过程。

ITERATE: walking through the loop

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP <-- 
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
    END LOOP;
END; //

这里的ITERATE(迭代)让循环又回到了循环的头部。

ITERATE: walking through the loop

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label; <-- 
    END IF;
END LOOP; 

END; //

  当v的值变为5时,程序将执行LEAVE语句

ITERATE: walking through the loop

CREATE PROCEDURE p20 ()
BEGIN
    DECLARE v INT;
    SET v = 0;
    loop_label: LOOP
    IF v = 3 THEN
        SET v = v + 1;
        ITERATE loop_label;
    END IF;
    INSERT INTO t VALUES (v);
    SET v = v + 1;
    IF v >= 5 THEN
        LEAVE loop_label;
    END IF;
END LOOP; 

END; // <-- 

LEAVE的结果就是跳出循环,使运行指令到达复合语句的最后一步。

GOTO
CREATE PROCEDURE p...
BEGIN
...
LABEL label_name;
...
GOTO label_name;
...
END;

  MySQL的存储过程中可以使用GOTO语句。虽然这不是标准SQL语句,而且在这里建立标号的方法也和惯例中的不一样。由于为了和其他DBMS兼容,这个语句会慢被淘汰,所以我们在MySQL参考手册中没有提及。

Grand combination

大组合 

CREATE PROCEDURE p21
(IN parameter_1 INT, OUT parameter_2 INT)
LANGUAGE SQL DETERMINISTIC SQL SECURITY INVOKER
BEGIN
    DECLARE v INT;
    label goto_label; start_label: LOOP
    IF v = v THEN LEAVE start_label;
    ELSE ITERATE start_label;
    END IF;
    END LOOP start_label;
    REPEAT
        WHILE 1 = 0 DO BEGIN END;
        END WHILE;
        UNTIL v = v;
    END REPEAT;
    GOTO goto_label;
END;//

  上面例子中的语句包含了我们之前讲的所有语法,包括参数列表,特性参数,BEGIN/END块复合语句,变量声明,IF,WHILE,LOOP,REPEAT,LEAVE,ITERATE,GOTO。这是一个荒谬的存储过程,我不会运行它,因为里面有无尽的循环。但是里面的语法却十分合法。这些是新的流程控制和变量声明语句。下面我们将要接触更多新的东西。

机器人 2007-11-9(整理) 于 北京

Mysql常用函数列表(收藏)

Posted by 机器人 on 1st 十一月 2007 in mysql

载自:http://blog.chinaunix.net/u/1222/showart_162319.html

HARSET(str) //返回字串字符集

CONCAT (string2  [,... ]) //连接字串

INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0

LCASE (string2 ) //转换成小写

LEFT (string2 ,length ) //从string2中的左边起取length个字符

LENGTH (string ) //string长度

LOAD_FILE (file_name ) //从文件读取内容

LOCATE (substring , string  [,start_position ] ) 同INSTR,但可指定开始位置

LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length

LTRIM (string2 ) //去除前端空格

REPEAT (string2 ,count ) //重复count次

REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str

RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length

RTRIM (string2 ) //去除后端空格

STRCMP (string1 ,string2 ) //逐字符比较两字串大小,

SUBSTRING (str , position  [,length ]) //从str的position开始,取length个字符,

TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符

UCASE (string2 ) //转换成大写

RIGHT(string2,length) //取string2最后length个字符

SPACE(count) //生成count个空格

 
数学类

ABS (number2 ) //绝对值

BIN (decimal_number ) //十进制转二进制

CEILING (number2 ) //向上取整

CONV(number2,from_base,to_base) //进制转换

FLOOR (number2 ) //向下取整

FORMAT (number,decimal_places ) //保留小数位数

HEX (DecimalNumber ) //转十六进制

LEAST (number , number2  [,..]) //求最小值

MOD (numerator ,denominator ) //求余

POWER (number ,power ) //求指数

RAND([seed]) //随机数

ROUND (number  [,decimals ]) //四舍五入,decimals为小数位数]

SIGN (number2 ) //返回符号,正负或0

SQRT(number2) //开平方

 
日期时间类
 
ADDTIME (date2 ,time_interval ) //将time_interval加到date2

CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区

CURRENT_DATE (  ) //当前日期

CURRENT_TIME (  ) //当前时间

CURRENT_TIMESTAMP (  ) //当前时间戳

DATE (datetime ) //返回datetime的日期部分

DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间

DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime

DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间

DATEDIFF (date1 ,date2 ) //两个日期差

DAY (date ) //返回日期的天

DAYNAME (date ) //英文星期

DAYOFWEEK (date ) //星期(1-7) ,1为星期天

DAYOFYEAR (date ) //一年中的第几天

EXTRACT (interval_name  FROM date ) //从date中提取日期的指定部分

MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串

MAKETIME (hour ,minute ,second ) //生成时间串

MONTHNAME (date ) //英文月份名

NOW (  ) //当前时间

SEC_TO_TIME (seconds ) //秒数转成时间

STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示

TIMEDIFF (datetime1 ,datetime2 ) //两个时间差

TIME_TO_SEC (time ) //时间转秒数]

WEEK (date_time [,start_of_week ]) //第几周

YEAR (datetime ) //年份

DAYOFMONTH(datetime) //月的第几天

HOUR(datetime) //小时

LAST_DAY(date) //date的月的最后日期

MICROSECOND(datetime) //微秒

MONTH(datetime) //月

MINUTE(datetime) //分

 

附:可用在INTERVAL中的类型

DAY ,DAY_HOUR ,DAY_MINUTE ,DAY_SECOND ,HOUR ,HOUR_MINUTE ,HOUR_SECOND ,MINUTE ,MINUTE_SECOND,MONTH ,SECOND ,YEAR

机器人 2007-11-1 于 北京

JOIN联表中ON,WHERE后面跟条件的区别

Posted by 机器人 on 24th 十月 2007 in mysql

对于JOIN的连表操作,这里就不细述了,当我们在对表进行JOIN关联操作时,对于ON和WHERE后面的条件,不清楚大家有没有注意过,有什么区别,可能有的朋友会认为跟在它们后面的条件是一样的,你可以跟在ON后面,如果愿意,也可以跟在WHERE后面。

这对于有的情况来讲,可能会是正确的,不过那种正确纯属于运气好,给撞上了。对于JOIN后面所跟条件,它们在ON和WHERE后面究竟有一个什么样的区别呢?

在JOIN操作里,有几种情况。LEFT JOIN,RIGHT JOIN,INNER JOIN等。

为了清楚的表达主题所描述的问题,我简要的对LEFT,RIGHT,INNER这几种连接方式作一个说明。

下面就拿一个普通的博客系统的日志表(post)和分类表(category)来描述吧。

这里我们规定有的日志可能没有分类,有的分类可能目前没有属于它的文章。

1.    LEFT JOIN:

(保证找出左联表中的所有行)

查出所有文章,并显示出他们的分类:

 

SELECT p.title,c.category_name FROM post p LEFT JOIN category c ON p.cid = c.cid

2.    RIGHT JOIN:

(保证找出右联表中的所有行)

查询所有的分类,并显示出该分类所含有的文章数。

 

SELECT COUNT(p.id),c.category_name FROM post p RIGHTJOIN  category c ON p.pid = c.cid

3.    INNER JOIN

(找出两表中关联相等的行)

查询有所属分类的日志。(即那些没有所性分类的日志文章将不要我们的查询范围之内)。

 

SELECT p.title,c.category_name FROM post p INNER JOIN category c ON p.cid = c.cid.

这种情况和直接两表硬关联等价。

现在我们回过头来看上面的问题。

对于第一种情况,如果我们所ON 的条件写在WHERE 后面,将会出现什么情况呢?

即:

 

SELECT p.title,c.category_name FROM post p LEFT JOIN category c WHERE  p.cid = c.cid

对于第二种情况,我们同样按照上面的书写方式。

 

SELECT COUNT(p.id),c.category_name FROM post p RIGHTJOIN  category c WHERE p.pid = c.cid

如果运行上面的SQL语句,就会发现,它们已经过滤掉了一些不满足条件的记录,可能在这里,大家会产生疑问了,不是用了LEFT和RIGHT吗?它们可以保证左边或者右边的所有行被全部查询出来,为什么现在不管用了呢?对于出现这种的问题,呵呵!是不是觉得有些不可思议。

出现这种的问题,原因就在WHERE和ON这两个关键字后面跟条件。

好了,现在我也不调大家味口了,给大家提示答案吧。

对于JOIN参与的表的关联操作,如果需要不满足连接条件的行也在我们的查询范围内的话,我们就必需把连接条件放在ON后面,而不能放在WHERE后面,如果我们把连接条件放在了WHERE后面,那么所有的LEFT,RIGHT,等这些操作将不起任何作用,对于这种情况,它的效果就完全等同于INNER连接。对于那些不影响选择行的条件,放在ON或者WHERE后面就可以。

记住:所有的连接条件都必需要放在ON后面,不然前面的所有LEFT,和RIGHT关联将作为摆设,而不起任何作用。

这个问题是前几天在我们phpoo讨论区里提的问题,一直没有写出比较详细的区别,其实这个问题完全可以用一句话描述清楚,那么,为什么我要在这里写上这么多啰嗦的话,主要是因为在对自己的知识进行巩固的同时,我也希望能给更多的朋友带来方便,而且现在我们的phpoo团队里各成员的水平参差不齐,所以为了照顾更多的人,才多啰嗦了这么几句,希望团里面的高手们不了笑话。

如果朋友你感兴趣:可以加入我们的论坛一起探讨该主题:http://bbs.phpexp.cn/viewthread.php?tid=79&extra=page%3D1

又快到11点了,完了,今天好像看不了书了。哎!没关系,和老单聊十几分钟天就休息。。

机器人 2007-10-24 10:43 于北京。

SQL:LEFT JOIN 多次连接同一张表

Posted by 机器人 on 22nd 十月 2007 in mysql

以前一直没有注意到LEFT JOIN 多次向同一表进行连接所带来的快捷,本来以为一条SQL语句实现不了,后来同事给指点了下,最后用了一条SQL语句给解决了。实在找不到比较容易的例子来说明这个问题,所以暂时只能先帖上SQL语句了,等那天想到了,再把详细清单给附上。

代码如下:

SELECT
    [募资公布日]=CONVERT(varchar(10),CFIP2,121),
    [发行起始日]=CONVERT(varchar(10),PublishDate,121),
    [发行截止日]=CONVERT(varchar(10),CFIP1,121), [发行方式]=CFIP28,
    [发行类型]=CFIP5,
    [发行前总份额]=CFIP7,
    [扩募比例]=CFIP6,
    [权益登记日]=CONVERT(varchar(10),CFIP14,121),
    [除权基准日]=CONVERT(varchar(10),CFIP15,121),
    [本次发行份额]=CFIP8,
    [单位面值]=CFIP9,
    [单位发行价]=CFIP10,
    [单位发行费用]=CFIP11,
    [募集资金合计]=CFIP17,
    [发起人认购]=CFIP12,
    [社会认购份额]=CFIP26,
    [发行中签率]=CFIP18,
    [认购倍数]=CFIP22,
    [扩募协调人]=ISNULL(p.FParty5,'-'),
    [上市推荐人]=ISNULL(p1. FParty5,'-'),
    [主承销商]=ISNULL(p2. FParty5,'-')
FROM CFIP c LEFT JOIN FParty p ON c.Symbol = p.Symbol AND  p.fparty1='发行协调人'
LEFT OUTER JOIN FParty p1 ON c.Symbol = p1.Symbol AND p1.fparty1='基金管理人'
LEFT JOIN FParty p2 ON c.Symbol = p2.Symbol AND p2.fparty1='主承销商'
WHERE c.Symbol = '500011'

 

这里需要说明的是当CFIP表多次向FPARTY表发出左关联,就能一次性取得FPARTY表中多条记录的值。

机器人 2007-10-22  10:29 于 北京 (准备休息了,一般在睡觉之前,总喜欢看上半小时的书,也就是说,我是晚11:00关灯睡觉

Can’t connect to local MySQL server through socket 解决办法

Posted by 机器人 on 23rd 九月 2007 in mysql

这种错误也不是什么新鲜的事了,为了让大家更能清楚发现这种情况的原因,所以我在这里还是总结一下在什么情况下会出现这种错误报告信息。。

mysqld.sock这个文件是在mysqld服务启动时会自动创建,我们对mysql的每一步操作,都是通过mysqld.sock这个文件来进行通信的。所以在执行每一条命令之前,都得检查该命令是否存在。

1.MYSQL服务没有启动

    在这里,我们只需要启动mysqld服务就行了。

 

[hqlong@localhost /]# /sbin/service mysqld start
启动 MySQL:                                               [确定]

2./var/lib/mysql目录没有权限。

    最常见的原因也就是这个原因了,由于目录没有mysql创建文件的权限,所以服务启动时,尝试创建mysqld.sock文件,由于没有相应的权限,所以创建就不会成功,当然在我们使用mysql时,由于找不到该文件,所以就出现了该错误。我们只需要对其权限进行更改就行了。如下:

 

[hqlong@localhost /]#  chmod -R 777 /var/lib/mysql

3.很我可能是你的磁盘没有空间,所以不能创建mysql.sock这个文件。

这种情况,出现的比较少,如果对服务器的存储容量没有合理设计的话,很有可能出现这样的问题,比如你的站点的访问量相当高,服务器将会为每一位访问都添加一条访问日志,如果我们没有定期对这些日期文件进行处理,那么很我可能日志文件将占用我们的所有空间,将导致最后没有空间来创建新的文件。

 

机器人 2007-9-23 于 北京.