【问题标题】:PostgreSQL 3 Table Join MultiplyingPostgreSQL 3 表连接乘法
【发布时间】:2017-07-07 08:00:36
【问题描述】:

我有 3 张桌子。第一个有我想要的记录。另外两个具有要应用于第一个表的类别。如果在描述中找到 table3 的查找值,我想返回该类别。否则,返回表 2 中的类别。我认为我的逻辑是正确的,但结果正在成倍增加。如何将结果限制为我想要的 table1 记录,但应用正确的类别?

这是我的带有示例架构的查询。它应该只返回 table1 中的前 6 行,无论哪个类别都是正确的,但它返回 10。http://sqlfiddle.com/#!15/fc6fa/49/0

SELECT table1.product_code, table1.date_signed, table1.description, 
CASE 
  WHEN lower(table1.description) LIKE ('%' || lower(table3.lookup_value) || '%') 
  THEN table3.category 
  ELSE table2.category 
END 
FROM table1 
LEFT JOIN table2 ON table2.psc_code = table1.product_code 
LEFT JOIN table3 ON table3.psc_code = table1.product_code 
WHERE date_signed = '2017-02-01';



create table table1 ( 
product_code int, 
date_signed timestamp, 
description varchar(20) 
); 

insert into table1 
(product_code, date_signed, description) 
values 
(1, '2017-02-01', 'i have a RED car'), 
(2, '2017-02-01', 'i have a blue boat'), 
(3, '2017-02-01', 'i have a dark cat'), 
(1, '2017-02-01', 'i have a green truck'), 
(2, '2017-02-01', 'i have a blue rug'), 
(3, '2017-02-01', 'i have a dark dog'), 
(1, '2017-02-02', 'i REd NO SHOW'), 
(2, '2017-02-02', 'i blue NO SHOW'), 
(3, '2017-02-02', 'i dark NO SHOW'); 

create table table2 ( 
psc_code int, 
category varchar(20) 
); 

insert into table2 
(psc_code, category) 
values 
(1, 'vehicle'), 
(2, 'vehicle'); 

create table table3 ( 
psc_code int, 
lookup_value varchar(20), 
category varchar(20) 
); 

insert into table3 
(psc_code, lookup_value, category) 
values 
(1, 'fox', 'animal'), 
(1, 'red', 'color'), 
(1, 'box', 'shipping'), 
(2, 'cat', 'animal');

【问题讨论】:

    标签: sql postgresql cartesian-product


    【解决方案1】:

    您正在尝试将 1 连接到多个,并且您只想要一个值。

    SELECT table1.product_code, table1.date_signed, table1.description,
    CASE 
      WHEN EXISTS (select 1 from table3
                   where table3.psc_code = table1.product_code and
                         lower(table1.description) LIKE ('%' || lower(table3.lookup_value) || '%')) 
      THEN (select table3.category from table3 
            where table3.psc_code = table1.product_code and
                  lower(table1.description) LIKE ('%' || lower(table3.lookup_value) || '%') limit 1)
      ELSE (select table2.category
            from table2
            where table2.psc_code = table1.product_code
            limit 1)
    END 
    FROM table1 
    WHERE date_signed = '2017-02-01';
    

    http://rextester.com/TQIY93378

    +--------------+---------------------+----------------------+----------+
    | product_code |     date_signed     |      description     | category |
    +--------------+---------------------+----------------------+----------+
    | 1            | 01.02.2017 00:00:00 | i have a RED car     | color    |
    | 2            | 01.02.2017 00:00:00 | i have a blue boat   | vehicle  |
    | 3            | 01.02.2017 00:00:00 | i have a dark cat    | NULL     |
    | 1            | 01.02.2017 00:00:00 | i have a green truck | vehicle  |
    | 2            | 01.02.2017 00:00:00 | i have a blue rug    | vehicle  |
    | 3            | 01.02.2017 00:00:00 | i have a dark dog    | NULL     |
    +--------------+---------------------+----------------------+----------+
    

    【讨论】:

    • 我看到它得到了正确的结果数量,但据我计算,product_code 3 不应该有一个类别,对吧?为什么它会在前 3 个中得到动物?
    • 谢谢,成功了!
    【解决方案2】:

    是的,你会在这个上得到一个笛卡尔积。

    您的问题是每个 product_code 的多行与 table1 匹配。因此,当您在 table3 上加入时,您会得到 6 条 id 为 1 的记录。其他加入条件不会造成双方都有多个匹配项的情况,所以这就是您获得 6 个产品代码 1 行 2 的方式产品代码 2 行和 2 产品代码 3 行。

    解决方案是以外键指向目标表中唯一行的方式进行连接。

    这确实应该是一个有用的例子,说明为什么规范化和关键意识很重要。如果你打破了函数依赖的基本规则,那么糟糕的问题就会成倍增加。

    【讨论】:

      猜你喜欢
      • 2010-11-28
      • 1970-01-01
      • 2015-03-24
      • 1970-01-01
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多