选择具有特殊条件和总和的多个表的行(类似于:show if)

时间:2014-05-13 07:45:10

标签: php mysql sql

我尝试在单个MySQL语句(在PHP脚本中使用)中找出以下场景:

有一个包含公共文章的商店数据库,向所有人展示(客户0)。有些客户可以获得一些特价商品(折扣)。最后一个选项是,客户A只能看到库存1中的库存量,客户B可以看到库存1和2中的物品数量。

我的问题是我希望通过公开文章和特殊客户文章显示客户的文章概述。如果客户A对第10000条有特殊条件,则不应显示公共文章,只显示特殊客户。

客户500需要以下结果:

article_no article_name length width customer_article_no price total_sum
------------------------------------------------------------------------
10000      Article One  10     10    123                 13.50        45
20000      Article Two  15     13                         1.25        10
30000      Article Three 25    25    456                 25.00        35

经过一些尝试后,我得到了以下结果(X是不想要的行):

article_no article_name length width customer_article_no price total_sum
------------------------------------------------------------------------
10000      Article One  10     10                        13.50        45    <- X
10000      Article One  10     10    123                 13.00        45
20000      Article Two  15     13                         1.25        10
30000      Article Three 25    25    456                 25.00        35

我的数据库结构如下:

pastebin

CREATE TABLE IF NOT EXISTS `article` (
  `article_no` int(11) NOT NULL,
  `article_name` varchar(255) COLLATE utf8_bin NOT NULL,
  `length` double NOT NULL,
  `width` double NOT NULL,
  PRIMARY KEY (`article_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `article` (`article_no`, `article_name`, `length`, `width`) VALUES
(10000, 'Article One', 10, 10),
(20000, 'Article Two', 15, 13),
(30000, 'Article Three', 25, 25);

CREATE TABLE IF NOT EXISTS `article_to_customer` (
  `article_no` int(11) NOT NULL,
  `customer_no` int(11) NOT NULL,
  `customer_article_no` varchar(25) COLLATE utf8_bin DEFAULT NULL,
  `price` double DEFAULT NULL,
  `public_article` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`article_no`,`customer_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `article_to_customer` (`article_no`, `customer_no`, `customer_article_no`, `price`, `public_article`) VALUES
(10000, 1, NULL, 13.5, 1),
(10000, 500, '123', 13, 0),
(20000, 1, NULL, 1.25, 1),
(30000, 500, '456', 25, 0);

CREATE TABLE IF NOT EXISTS `customer` (
  `customer_no` int(11) NOT NULL,
  `customer_name` varchar(255) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`customer_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;


INSERT INTO `customer` (`customer_no`, `customer_name`) VALUES
(1, 'PUBLIC'),
(500, 'CustomerNo1'),
(1001, 'CustomerNo2');


CREATE TABLE IF NOT EXISTS `customer_to_stock` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_no` int(11) NOT NULL,
  `stock_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `stock` (
  `stock_id` int(11) NOT NULL AUTO_INCREMENT,
  `stock_name` varchar(255) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`stock_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;


INSERT INTO `stock` (`stock_id`, `stock_name`) VALUES
(1, 'Germany'),
(2, 'Poland');


CREATE TABLE IF NOT EXISTS `stocked` (
  `stock_id` int(11) NOT NULL,
  `article_no` int(11) NOT NULL,
  `stocked` int(11) NOT NULL,
  PRIMARY KEY (`stock_id`,`article_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;


INSERT INTO `stocked` (`stock_id`, `article_no`, `stocked`) VALUES
(1, 10000, 12),
(1, 20000, 10),
(1, 30000, 0),
(2, 10000, 33),
(2, 20000, 0),
(2, 30000, 35);

我尝试了几个连接:

SELECT a.article_no, a.article_name, a.length, a.width,
atc.customer_article_no, atc.price,
(SELECT SUM(sa.stocked) FROM stocked AS sa WHERE (sa.stock_id = 1 OR sa.stock_id = 2) AND sa.article_no = atc.article_no GROUP BY article_no) AS total_sum
FROM article AS a
JOIN article_to_customer AS atc
ON atc.article_no = a.article_no AND (atc.customer_no = 500 OR atc.customer_no = 0)

SELECT a.article_no, a.article_name, a.length, a.width,
atc.customer_article_no, atc.price,
(SELECT SUM(sa.stocked) FROM stocked AS sa WHERE (sa.stock_id = 1 OR sa.stock_id = 2) AND sa.article_no = atc.article_no GROUP BY article_no) AS total_sum
FROM article AS a
JOIN article_to_customer AS atc
ON atc.article_no = a.article_no AND (atc.customer_no = 500 OR atc.customer_no = 0)
GROUP BY atc.public_article

但我无法得到想要的结果。

因此,快速概述中的条件:选择article_to_customer表中编写的所有文章,并对存储的金额求和。如果存在特殊的客户条件(如自己的客户编号或不同的价格),请仅显示客户文章版本并忽略公开文章。

请记住:数据库结构只是一个没有外键和许多数据的最小示例。如果需要,可以更改结构。

1 个答案:

答案 0 :(得分:1)

要将这种最佳匹配连接拆分为两个连接:

FROM article AS a
LEFT JOIN article_to_customer AS atc1
ON atc1.article_no = a.article_no 
AND atc1.customer_no = 500
LEFT JOIN article_to_customer AS atc2
ON atc2.article_no = a.article_no 
AND atc2.public_article = 1

然后你必须为SELECT列表中的act添加每列的COALESCE:

COALESCE(atc1.customer_article_no, atc2.customer_article_no),
COALESCE(atc1.price, atc2.price)

如果你有article_to_customer中不存在的文章,你可能需要添加另一个条件才能获得与内连接相同的结果:

WHERE (atc1.article_no IS NOT NULL OR atc2.article_no IS NOT NULL)