SQL水平测试题目三道(二)

补充:count(1)和count(*)基本没有差别!可以在网上搜索下.

如果你的数据表没有主键,那么count(1)比count(*)快
如果有主键的话,那主键(联合主键)作为count的条件也比count(*)要快
如果你的表只有一个字段的话那count(*)就是最快的啦
count(*) count(1) 两者比较。主要还是要count(1)所相对应的数据字段。
如果count(1)是聚索引,id,那肯定是count(1)快。但是差的很小的。
因为count(*),自动会优化指定到那一个字段。所以没必要去count(?),用count(*),sql会帮你完成优化的

 

原题:

1.有表A,结构如下:

A: p_ID p_Num s_id
    1 10 01
    1 12 02
    2 8 01
    3 11 01
    3 8 03
其中:p_ID为产品ID,p_Num为产品库存量,s_id为仓库ID。请用SQL语句实现将上表中的数据合并,合并后的数据为:
p_ID s1_id s2_id s3_id
    1 10 12 0
    2 8 0 0
    3 11 0 8

其中:s1_id为仓库1的库存量,s2_id为仓库2的库存量,s3_id为仓库3的库存量。如果该产品在某仓库中无库存量,那么就是0代替。

OK,现在到MySQL进行表的建立:

-- ----------------------------
-- Table structure for `a`
-- ----------------------------
DROP TABLE IF EXISTS `a`;
CREATE TABLE `a` (
  `p_id` int(11) DEFAULT NULL,
  `p_num` int(11) DEFAULT NULL,
  `s_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of a
-- ----------------------------
INSERT INTO `a` VALUES ('1', '10', '1');
INSERT INTO `a` VALUES ('1', '12', '2');
INSERT INTO `a` VALUES ('2', '8', '1');
INSERT INTO `a` VALUES ('3', '11', '1');
INSERT INTO `a` VALUES ('3', '8', '3');

SQL水平测试题目三道(二)_第1张图片如图,左侧是建立后的表,题目要求为行转列为右侧表.

正确的SQL语句如下:

select p_id,
sum(case s_id when 1 then p_num else 0 end) as s1_id,
sum(case s_id when 2 then p_num else 0 end) as s2_id,
sum(case s_id when 3 then p_num else 0 end) as s3_id
from A group by p_id

思路:擦,其实就是个简单的行转列.不过是加了个sum和group by.(PS:数据库默认关键字是大小写,不过我是先在txt上敲的).理解SQL执行顺序很重要.


2.表结构如下: 

企业名称 欠费金额 是否欠费 
a 120 未 
b 120 是 
c 60 未 
a 120 是 
a 120 是 
b 120 未 

要取如下格式 该怎么写sql 语句(注意:列名都使用中文对应的英文命名) 
企业名称 应缴金额 实缴金额 欠费金额 是否欠费 
a 360 120 240 是 
b 240 120 120 是 
c 60 60 0 未 

照旧先建表:
DROP TABLE IF EXISTS `b`;
CREATE TABLE `b` (
  `企业名称` varchar(255) DEFAULT NULL,
  `欠费金额` int(11) DEFAULT NULL,
  `是否欠费` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of b
-- ----------------------------
INSERT INTO `b` VALUES ('a', '120', 'n');
INSERT INTO `b` VALUES ('b', '120', 'y');
INSERT INTO `b` VALUES ('c', '60', 'n');
INSERT INTO `b` VALUES ('a', '120', 'y');
INSERT INTO `b` VALUES ('a', '120', 'y');
INSERT INTO `b` VALUES ('b', '120', 'n');

表图如左,要求如右
SQL水平测试题目三道(二)_第2张图片

SQL语句答案如下:
select 
temp.企业名称,temp.应缴金额,temp.实缴金额,temp.欠缴金额,
(case when temp.欠缴金额>0 then "欠费" else "没欠" end)as "是否欠费" 
from(
select 企业名称,
sum(欠费金额) as "应缴金额",
sum(case 是否欠费 when "N" then 欠费金额 else 0 end) as "实缴金额",
sum(case 是否欠费 when "Y" then 欠费金额 else 0 end) as "欠缴金额"
from b  group by 企业名称
)temp

PS:好吧,我很可耻的偷懒了,列名都搞中文的...........
思路:首先要说的就是是否欠费实际上是要计算一下的,不过按照题目的意思,费用方面已经计算了.
    1.首先,先确定case when的思路,为主体查出数据所需要的.case when确定.
    2.需要按企业名称进行分组.group by 企业名称 确定. 需要求SUM. sum确定.
    3.因此,主题数据可以查询出了.
顺利查出:
select 企业名称,
sum(欠费金额) as "应缴金额",
sum(case 是否欠费 when "N" then 欠费金额 else 0 end) as "实缴金额",
sum(case 是否欠费 when "Y" then 欠费金额 else 0 end) as "欠缴金额"
from b  group by 企业名称

但是仍然是不符合题目要求的.
1.需要用case when判断下欠缴金额是否大于0.因此此题就搞出来了.相当于把上面图再做一次查询.并判断下.结果图在上面.

3.表结构如下: 

表A: Employee_sn StartDate EndDate 
1 '2007-01-02' '2007-01-03' 
1 '2007-01-05' '2007-01-06' 
1 '2007-01-09' '2007-01-13' 
2 '2007-02-02' '2007-02-03' 
3 '2007-04-02' '2007-04-03' 

表B: Employee_sn CreateDate 
1 '2007-01-02' 
1 '2007-01-05' 
1 '2007-01-03' 
3 '2007-04-02' 
1 '2007-01-04' 
1 '2007-01-02' 
2 '2007-02-02' 

要得到的结果: 
Employee_sn StartDate EndDate Count 
1 '2007-01-02' '2007-01-03' 3 
1 '2007-01-05' '2007-01-06' 1 
1 '2007-01-09' '2007-01-13' 0 
2 '2007-02-02' '2007-02-03' 1 
3 '2007-04-02' '2007-04-03' 1 

注:根据表A中的时间段和员工编号到表B中去统计出对应的员工在该时间段的记录总数. 
表A中的员工可能会有多个时间段,但时间段彼此不会重复.

照旧先建表:
DROP TABLE IF EXISTS `first`;
CREATE TABLE `first` (
  `id` int(11) DEFAULT NULL,
  `startTime` date DEFAULT NULL,
  `endTime` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of first
-- ----------------------------
INSERT INTO `first` VALUES ('1', '2007-01-02', '2007-01-03');
INSERT INTO `first` VALUES ('1', '2007-01-05', '2007-01-06');
INSERT INTO `first` VALUES ('1', '2007-01-09', '2007-01-13');
INSERT INTO `first` VALUES ('2', '2007-02-02', '2007-02-03');
INSERT INTO `first` VALUES ('3', '2007-04-02', '2007-04-03');

-- ----------------------------
-- Table structure for `second`
-- ----------------------------
DROP TABLE IF EXISTS `second`;
CREATE TABLE `second` (
  `id` int(11) DEFAULT NULL,
  `createTime` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of second
-- ----------------------------
INSERT INTO `second` VALUES ('1', '2007-01-02');
INSERT INTO `second` VALUES ('1', '2007-01-05');
INSERT INTO `second` VALUES ('1', '2007-01-03');
INSERT INTO `second` VALUES ('3', '2007-04-02');
INSERT INTO `second` VALUES ('1', '2007-01-04');
INSERT INTO `second` VALUES ('1', '2007-01-02');
INSERT INTO `second` VALUES ('2', '2007-02-02');

如图:
SQL水平测试题目三道(二)_第3张图片
需要查询出的结果图如下:
SQL水平测试题目三道(二)_第4张图片
正确的SQL语句为:
select f.id,f.startTime,f.endTime,
(select count(*)
from second as s
WHERE f.id=s.id 
and s.createTime BETWEEN f.startTime AND f.endTime 
)
AS '次数'
from first as f 

思路分析:
1.首先肯定确定between and 思路的确定,具体怎么用,先不想.
2.首先可以确定,first表中数据是都在的,需要用between and判断second的时间,然后进行count的计算.
3.OK,现在就是select f.id,f.startTime,f.endTime, 以及  from first as f  Order by f.id 思路的确定.
4.剩下的就是在前端查询中,如何有效的查询出count.
5.行数是计算second表的各种数据的行数,那么主查的肯定就是second表了. select count(*) from second as s 确定.
6.接着就是where条件该怎么写了.首先, where f.id=s.id是确定不变的.
7.判断符合count计算,要判断时间,那么whereEx就有 s.createTime between f.startTime and f.endTime.
8.OK.其实order by可以不要的,默认就是f.id排序.

题外话:如果使用了group by分组的话,count是会查出null来的,而不会是0,处理如下处理(用mysql的IFNULL(xx,0)):
注:group by其实消耗性能,这题这种查询是不需要的.因此IFNULL这个控制函数也可以不写.
select f.id,f.startTime,f.endTime,
IFNULL((select count(*)
from second as s
WHERE f.id=s.id 
and s.createTime BETWEEN f.startTime AND f.endTime 
GROUP BY f.id,f.startTime,f.endTime ),0)AS '次数'
from first as f 

OK,三道题完成.

你可能感兴趣的:(sql,mysql,测试,count(*),count(1))