1.笛卡爾集
創建倆表:
-- 創建部門表(dept)
use mysql_learn
CREATE TABLE dept (deptno INT PRIMARY KEY, dname VARCHAR(50) NOT NULL, loc VARCHAR(50)
);-- 創建員工表(emp)
CREATE TABLE emp (empno INT PRIMARY KEY, ename VARCHAR(50) NOT NULL, job VARCHAR(50), mgr INT, hiredate DATE, sal DECIMAL(10,2) NOT NULL, comm DECIMAL(10,2), deptno INT
);
插入一些示例數據:
-- 向部門表插入數據
INSERT INTO dept (deptno, dname, loc) VALUES
(10, 'ACCOUNTING', 'NEW YORK'),
(20, 'RESEARCH', 'DALLAS'),
(30, 'SALES', 'CHICAGO'),
(40, 'OPERATIONS', 'BOSTON');-- 向員工表插入數據
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800.00, NULL, 20),
(7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600.00, 300.00, 30),
(7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30),
(7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975.00, NULL, 20),
(7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30),
(7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850.00, NULL, 30),
(7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450.00, NULL, 10),
(7788, 'SCOTT', 'ANALYST', 7566, '1982-12-09', 3000.00, NULL, 20),
(7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000.00, NULL, 10),
(7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500.00, 0.00, 30),
(7876, 'ADAMS', 'CLERK', 7788, '1983-01-12', 1100.00, NULL, 20),
(7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950.00, NULL, 30),
(7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000.00, NULL, 20),
(7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300.00, NULL, 10);
看看結果:
部門表,里面有4條記錄。
雇員表,里面有14條記錄。
假設現在有個需求:打印某個員工的工資條。
我們有兩張表:1??雇員表,2??部門表。
當我們根據前面所學習的知識直接對兩個表同時查詢時會出現以下情況:
SELECT * from dept,emp
可以看到,我們直接將倆表連起來一起查出來的記錄有56條之多。
仔細探查我們會發現,這些結果實際上就是第一個表中的四條記錄和第二張表的一條記錄進行拼接而成的。也就是4*14=56條記錄。這就是笛卡爾集。
所以這些直接進行查詢獲得的信息是有冗余的信息,為了得到真正有意義的信息,我們需要做的就是過濾。
2.笛卡爾集的解決
為了過濾出有意義的信息,我們直接在where子句中做即可。
SELECT * from dept,empwhere dept.deptno = emp.deptno
這樣我們就解決了笛卡爾集,得到了真正有意義的14條記錄。
對sql語句稍作修改,也就可以得到每個員工的工資條了。
SELECT ename as '姓名',job as '工作',sal as '薪水',dname as '部門',deptno as '部門號'from dept,empwhere dept.deptno = emp.deptno
我們會發現這樣會報錯。
SQL 錯誤 [1052] [23000]: Column 'deptno' in field list is ambiguous
因為我們進行的是多表查詢,deptno這個字段在倆表中同時存在,直接寫會有歧義的。
我們對sql再次進行修改:
SELECT ename as '姓名',job as '工作',sal as '薪水',dname as '部門',emp.deptno as '部門號'from dept,empwhere dept.deptno = emp.deptno
得到了我們想要的結果了。
注意:多表查詢的條件不能少于表的個數減一,否則就會出現笛卡爾集。
3.練習
再創建一個工資等級表。
CREATE TABLE grade_salary (grade INT,losal DECIMAL(10, 2),hisal DECIMAL(10, 2)
);INSERT INTO grade_salary (grade, losal, hisal)
VALUES
(1, 1000.00, 1200.00),
(2, 1201.00, 2000.00),
(3, 2001.00, 3000.00),
(4, 3001.00, 9999.00),
(5, 3001.00, 9999.00);
(1)顯示各個員工的姓名,工資,工資等級
SELECT ename,sal,gradefrom emp,grade_salary
很顯然,直接查倆個表會出現笛卡爾集。
我們做一下過濾:可以直觀的分析出雇員表emp和工資級別表grade_salary之間的聯系就是員工工資在工資級別表中的那一個級別區間,也即員工工資和工資級別區間相對應的記錄就是我們要查詢的結果。
基于此,可以使用between and 語句來判斷。
SELECT ename,sal,gradefrom emp,grade_salary gswhere sal between losal and hisal;
(2)顯示員工名字,工資,所在部門名字,并按部門號降序排列
顯然我們這次需要查詢,emp和dept這兩張表,為了防止出現笛卡爾集,做一下過濾,最后用order by做一下排序。
SELECT ename,sal,dnamefrom emp e,dept dwhere e.deptno = d.deptnoorder by d.deptno DESC ;
、
再看一眼,按部門號降序排序也做好了。