楼主: newkid

[精华] SQL解惑(第2版) 的一些样题

[复制链接]
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
61#
 楼主| 发表于 2010-3-23 23:19 | 只看该作者
谜题6 预订旅馆房间

这篇是纯转帖,里面有个实现表约束的方法很巧妙,值得学习。

说的是有一张表存储每个旅馆房间的预定情况:
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
arrival_date DATE NOT NULL,    ---- 入住日期
departure_date DATE NOT NULL,  ---- 离开日期
guest_name CHAR(30) NOT NULL,
PRIMARY KEY (room_nbr, arrival_date),
CHECK (departure_date >= arrival_date)
);

现在要实现的是每两条记录之间不允许出现入住时间区间的重叠。

Answer #1
这是别的数据库的方法,ORACLE中不支持。
One solution requires a product to have the capability of using fairly
complex SQL in the CHECK() clause, so you will find that a lot of
implementations will not support it.
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
arrival_date DATE NOT NULL,
departure_date DATE NOT NULL,
guest_name CHAR(30),
PRIMARY KEY (room_nbr, arrival_date),
CHECK (departure_date >= arrival_date),
CHECK (NOT EXISTS
(SELECT *
FROM Hotel AS H1, Hotel AS H2
WHERE H1.room_nbr = H2.room_nbr
AND H1.arrival_date
BETWEEN H2.arrival_date AND
H2.departure_date)));

Answer #2
Another solution is to redesign the table, giving a row for each day and
each room, thus:
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
occupy_date DATE NOT NULL,
guest_name CHAR(30) NOT NULL,
PRIMARY KEY (room_nbr, occupy_date, guest_name));
如果住10天就会有10条记录,这个不推荐。


Answer #3
Lothar Flatz, an instructor for Oracle Software Switzerland, made the
objection that the clause "H1.arrival_date BETWEEN
H2.arrival_date AND H2.depatures" does not allow for a guest name
to arrive the same day another guest name leaves.
Since Oracle cannot put subqueries into CHECK() constraints and
triggers would not be possible because of the mutating table problem, he
used a VIEW that has a WITH CHECK OPTION to enforce the occupancy
constraints:

CREATE VIEW HotelStays (room_nbr, arrival_date,
departure_date, guest_name)
AS SELECT room_nbr, arrival_date, departure_date,
guest_name
FROM Hotel AS H1
WHERE NOT EXISTS
(SELECT *
FROM Hotel AS H2
WHERE H1.room_nbr = H2.room_nbr
AND H2.arrival_date < H1.arrival_date
PUZZLE 6 HOTEL RESERVATIONS 23
AND H1.arrival_date < H2.departure_date)
WITH CHECK OPTION;

For example,
INSERT INTO HotelStays
VALUES (1, '2008-01-01', '2008-01-03', 'Coe');
COMMIT;
INSERT INTO HotelStays
VALUES (1, '2008-01-03', '2008-01-05', 'Doe');
will give a WITH CHECK OPTION clause violation on the second INSERT
INTO statement. This is a good trick for getting table-level constraints in
a table on products without full SQL-92 features.

最后一个方法是个很好的技巧,他使用了WITH CHECK OPTION的视图来实现约束。注意对表的插入和修改都必须改成对视图操作。但是读数据还是从表来,才不会无端多了个NOT EXISTS的开销。

如果不用这个方法,那就得用触发器或者在应用中写校验代码,全都是复杂而且低效的方法。

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
62#
发表于 2010-3-24 08:27 | 只看该作者
#60的解在9i报递归SQL临时表空间(40M)不足错误

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
63#
 楼主| 发表于 2010-3-24 22:26 | 只看该作者
哦?9i下计划有什么不同?
把第一个WITH加上提示会怎样?
WITH w AS (SELECT /*+ materialize */ ROWNUM i FROM DUAL CONNECT BY ROWNUM<=8)

使用道具 举报

回复
论坛徽章:
8
授权会员
日期:2008-09-01 09:46:23祖国60周年纪念徽章
日期:2009-10-09 08:28:002010新春纪念徽章
日期:2010-01-04 08:33:082010年世界杯参赛球队:加纳
日期:2010-05-27 09:47:352011新春纪念徽章
日期:2011-01-04 10:26:43奥运会纪念徽章:花样游泳
日期:2012-06-26 09:57:17ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:152013年新春福章
日期:2013-02-25 14:51:24
64#
发表于 2010-3-25 21:46 | 只看该作者
太牛了,学习。

使用道具 举报

回复
论坛徽章:
2
2010新春纪念徽章
日期:2010-03-01 11:06:23优秀写手
日期:2014-02-09 06:00:12
65#
发表于 2010-4-3 17:50 | 只看该作者
mark,找个时间慢慢领会

使用道具 举报

回复
论坛徽章:
55
沸羊羊
日期:2015-04-03 16:29:392013年新春福章
日期:2013-02-25 14:51:24奥运会纪念徽章:乒乓球
日期:2012-10-16 21:48:05奥运会纪念徽章:举重
日期:2012-10-13 21:56:40ITPUB 11周年纪念徽章
日期:2012-10-09 18:13:33奥运会纪念徽章:水球
日期:2012-06-22 21:14:48奥运会纪念徽章:射箭
日期:2012-06-22 13:48:20双黄蛋
日期:2012-01-10 11:13:052012新春纪念徽章
日期:2012-01-04 11:55:23ITPUB十周年纪念徽章
日期:2011-11-01 16:25:22
66#
发表于 2010-4-5 22:45 | 只看该作者
先copy 下来,慢慢看~

使用道具 举报

回复
论坛徽章:
0
67#
发表于 2010-4-7 17:14 | 只看该作者
谢分享

使用道具 举报

回复
68#
发表于 2010-4-9 18:18 | 只看该作者
学习了#46促销,明白了
RANK() OVER(PARTITION BY promo_name ORDER BY SUM(sale_amt) DESC) RNK  --可以并列第一
row_number () over(PARTITION BY promo_name ORDER BY SUM(sale_amt) DESC) RNK --第一只有一个
不错不错,继续学习。
强大的分析函数。

使用道具 举报

回复
论坛徽章:
211
国际米兰
日期:2010-01-11 10:26:28ITPUB评论家
日期:2007-11-04 01:35:51季节之章:春
日期:2011-04-03 16:30:30热刺
日期:2009-09-21 10:54:48天枰座
日期:2015-11-05 16:32:03月度论坛发贴之星
日期:2010-05-01 02:15:42生肖徽章:狗
日期:2006-10-01 00:29:23BLOG每周发帖之星
日期:2009-08-30 01:35:31BLOG每日发帖之星
日期:2009-08-28 01:01:02妮可·罗宾
日期:2016-10-19 10:45:04
69#
发表于 2010-4-14 14:52 | 只看该作者
第一页还没看完

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
70#
 楼主| 发表于 2010-4-22 08:32 | 只看该作者
继续60楼的谜题67:婚姻稳定问题
我刚刚装好11GR2,就用新特性“带递归的WITH子查询”来做一下, 把它的7个子查询用递归实现:

WITH w AS (SELECT ROWNUM i FROM DUAL CONNECT BY ROWNUM<=8)
,p AS (
SELECT SUBSTR(h.man,2) AS h,SUBSTR(w.woman,2) AS w,h.ranking hr,w.ranking wr
  FROM Husbands h, Wives w
WHERE h.man=w.man and h.woman = w.woman
)
,b AS ( --- 求出所有不稳定的过滤表达式。
SELECT /*+ materialize */
       LPAD(p1.w,p1.h,'_')||LPAD(p2.w,p2.h-p1.h,'_')  bad
  FROM p p1,p p2, p p3, p p4
WHERE p1.h<p2.h  
       AND p1.w<>p2.w
       AND p1.h=p3.h AND p1.w=p4.w AND p2.h=p4.h AND p2.w=p3.w
       AND (p1.hr>p3.hr AND p2.wr>p3.wr
            OR p2.hr>p4.hr AND p1.wr>p4.wr
            )
)
,t2(a,c,lvl) AS (
    SELECT SUBSTR('12345678', i, 1) a,SUBSTR('12345678',1,i-1)||SUBSTR('12345678',i+1) c, 1 AS lvl
      FROM w
    UNION ALL
    SELECT CAST(a || SUBSTR(c , i , 1) AS VARCHAR2(10)) a,CAST(SUBSTR(c,1,i-1)||SUBSTR(c,i+1) AS VARCHAR2(10)) c,lvl+1
      FROM w,t2
     WHERE w.i<=8-t2.lvl
           AND NOT EXISTS (SELECT 1 FROM b WHERE a || SUBSTR(c , i , 1) LIKE b.bad)
           -- AND t2.lvl=(SELECT MAX(lvl) FROM t2) ---- 此处功能不支持
           AND t2.lvl<8
)
SELECT a FROM t2 WHERE lvl=8;

A
----------
74381526
24381576
24317586
63481572
64381572
36481572
63417582
64317582
36417582

9 rows selected.

这里面有个问题,每次递归时我们希望仅仅留下最外层的数据,但是我没有办法去掉其它的,这样就造成许多不必要的连接开销。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表