设为首页 收藏本站
查看: 668|回复: 0

[经验分享] SQL连接——笛卡尔积

[复制链接]

尚未签到

发表于 2018-10-14 12:01:31 | 显示全部楼层 |阅读模式
  最近在用几张表连接起来查询的时候发现有时会得到一模一样的数据,有时却不会,为了搞清楚这是怎么回事,特地学习了一下关于笛卡尔积与连接相关的知识。
  所谓的笛卡尔积,也就是笛卡尔乘积,因此如果是普通的两张表连接,就是将2张表乘起来显示,如有以下2张表:
  number:
  id
  value
  1
  100
  2
  150
  string:
  Id
  value
  1
  hello
  2
  hi
  输入select number.*, string.* from number, string;语句,将得到:
  number.id
  number.value
  string.id
  string.value
  1
  100
  1
  hello
  1
  100
  2
  hi
  2
  150
  1
  hello
  2
  150
  2
  hi
  同样的,如果再多一张表,比如说是有3条记录的表,那么三张表连接得到的将是2*2*3 = 12条记录,这就是所谓的笛卡尔乘积。
  等值连接就是在笛卡尔乘积的基础上剔除不相等的记录,如:
  输入select number.*, string.* from number, string where number.id = string.id;语句,sql将根据条件number.id = string.id这个等值关系将这两个值不相等的记录剔除,得到
  number.id
  number.value
  string.id
  string.value
  1
  100
  1
  hello
  2
  150
  2
  hi
  笛卡尔积就简单介绍完了,接着说什么时候会出现一模一样的表,这时又应该怎么办?
  假如有以下三张表:
  game:
  id
  name
  1001
  LG20120801
  winning:
  game_id
  serial_no
  level
  prize
  1001
  20120801001
  1
  100000
  1001
  20120801020
  2
  10000
  1001
  20120801300
  3
  1000
  prize_statistics
  game_id
  level
  count
  prize
  1001
  1
  1
  100000
  1001
  2
  1
  10000
  1001
  3
  1
  1000
  这里第二张是中奖信息表,第三张表是中奖统计表,当然了,这里只列出其中一个game的信息,事实上可能有很多game, 这里只以一个game来介绍查询情况,所以只列出一个game的信息即可,如果要查询详细的中奖情况,则输入:
  select g.name,
  w.serial_no,
  w.level,
  p.count,
  p.prize,
  from game g, winning w, prize_statistics p
  where g.id = w.game_id
  and w.game_id = p.game_id
  and w.level = p.level;
  这时得到:
  name
  serial_no
  level
  count
  prize
  LG20120801
  20120801001
  1
  1
  100000
  LG20120801
  20120801020
  2
  1
  10000
  LG20120801
  20120801300
  3
  1
  1000
  这里得到的结果是不会重复的,那什么情况下会出现重复的记录呢
  假如上面game表改一下:
  game:
  id
  name
  1001
  LG20120801
  1002
  LG20120802
  输入:
  select g.name,
  w.serial_no,
  w.level,
  p.count,
  p.prize,
  from game g, winning w, prize_statistics p
  where w.game_id = p.game_id
  and w.level = p.level;
  得到:
  name
  serial_no
  level
  count
  prize
  LG20120801
  20120801001
  1
  1
  100000
  LG20120801
  20120801020
  2
  1
  10000
  LG20120801
  20120801300
  3
  1
  1000
  LG20120802
  20120801001
  1
  1
  100000
  LG20120802
  20120801020
  2
  1
  10000
  LG20120802
  20120801300
  3
  1
  1000
  如果这时不列出game name的话就得到:
  serial_no
  level
  count
  prize
  20120801001
  1
  1
  100000
  20120801020
  2
  1
  10000
  20120801300
  3
  1
  1000
  20120801001
  1
  1
  100000
  20120801020
  2
  1
  10000
  20120801300
  3
  1
  1000
  这样就得到3个2条一模一样的记录,如果要得到唯一的数据,可以用distinct过一遍,也就是:
  select distinct g.name,
  w.serial_no,
  w.level,
  p.count,
  p.prize,
  from game g, winning w, prize_statistics p
  where w.game_id = p.game_id
  and w.level = p.level;
  不过这里不建议这么做,在数据的表中,一般记录都是唯一的,这时用连接查出来的结果也应该是唯一的,在少输出某些条件的情况下可能得到看似一样的数据,但是事实上并不是一样的(这跟上面的情况不一样),所以用distinct时会把这些数据给过滤掉,因此正确的作法是先确定一下在数据库中所查询的表里面的记录是不是唯一的,如果是唯一的而用连接查询到多条一样的记录的话那么有可能是因为少输出某些条件,也有可能是因为查询语句不正确,上面就是因为查询语句不正确导致的,这里少了判断game.id = winning.game_id这个条件,如果加上这个条件就正确了,在使用多表连接时最常出现的错误的就是where语句少判断条件,往往是多张表,只写了2张表的等值关系,正确的做法应该是如果有多张表的话,在where语句中要涉及到每张表,不能少了某张表。像我上次要查LG20120801这个游戏的中奖情况,使用以下查询语句:
  select gi.game_instance_name,
  gi.draw_date,
  w.ticket_serialno,
  ws.prize_level,
  ws.prize_number,
  ws.prize_amount,
  ws.actual_payout
  from winning_statistics ws, game_instance gi, winning w
  where ws.game_instance_id = gi.game_instance_id
  and w.game_instance_id = gi.game_instance_id –-ws, w, gi都涉及
  and w.prize_level = ws.prize_level
  and w.version = gi.version –-w, gi, ws 都要涉及到
  and ws.version = w.version –-少了这个条件,找了半天才发现,加上后结果就正确了。
  and gi.game_instance_name = 'LG20120801'
  order by gi.game_instance_name, ws.prize_level;
  连接就讲到这里了,接着说说distinct。上面我说连接查询的时候尽量不要用distinct,那distinct什么时候用呢,如果确定记录是一模一样的时候,去掉这些重复的记录时就派上用场了,最简单的一个用法,如我要查看一下当前的时间,这时我用:
  select sysdate from winning;
  这时sql会查询出N(N=winning的记录数)条记录出来,而且内容全部都是当前时间,这时应该用
  select distinct sysdate from winning;
  这时就得到我们想要的系统时间了。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-621465-1-1.html 上篇帖子: SQL Server -- Oracle,Access,SQL Server数据查询表索引等,列名对比 下篇帖子: SQL 2017 SQLPS执行Add-SqlAvailabilityDatabase异常
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表