Mysql 我的想法是错误的
我有以下场景:有一个带书籍的表和两对带销售订单和采购订单事务的表(HD/IT),通过销售订单id连接。 表格结构如下:Mysql 我的想法是错误的,mysql,Mysql,我有以下场景:有一个带书籍的表和两对带销售订单和采购订单事务的表(HD/IT),通过销售订单id连接。 表格结构如下: CREATE TABLE `books` ( `id` int(11) NOT NULL AUTO_INCREMENT, `isbn` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `it_id` int(11) NOT NULL, `kind` tinyint(4) NOT NULL, PRIMARY KEY
CREATE TABLE `books` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`isbn` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`it_id` int(11) NOT NULL,
`kind` tinyint(4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `books` (`id`, `isbn`, `it_id`, `kind`) VALUES
(1, '12345', 1, 1),
(2, '12345', 1, 2),
(3, '67890', 2, 1),
(4, '1111111', 2, 2);
CREATE TABLE `porders_hd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dt` date NOT NULL,
`so_id` int(11) DEFAULT NULL,
`customer` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `porders_hd` (`id`, `dt`, `so_id`, `customer`) VALUES
(1, '2017-07-02', 1, 1),
(2, '2017-08-03', NULL, 3);
CREATE TABLE `porders_it` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hd_id` int(11) NOT NULL,
`isbn` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`dscr` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`qty` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `porders_it` (`id`, `hd_id`, `isbn`, `dscr`, `qty`) VALUES
(1, 1, '12345', 'Book 1', 1),
(2, 2, '1111111', 'Book 2', 1);
CREATE TABLE `sorders_hd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dt` date NOT NULL,
`customer` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `sorders_hd` (`id`, `dt`, `customer`) VALUES
(1, '2017-07-01', 1),
(2, '2017-08-01', 2);
CREATE TABLE `sorders_it` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hd_id` int(11) NOT NULL,
`isbn` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`dscr` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`qty` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `sorders_it` (`id`, `hd_id`, `isbn`, `dscr`, `qty`) VALUES
(1, 1, '12345', 'Book 1', 1),
(2, 2, '67890', 'Book 2', 1);
概括而言,有:
*1个销售订单(#1)也存在于采购订单(#1)中
*1个销售订单(#2)仍在等待处理
*1个未创建销售订单的采购订单(#2)
我想能够抓住每本书的isbn和连接的SO和PO必须在同一行的所有销售和采购订单。输出必须如下所示:
so_id so_date po_id po_date isbn dscr
NULL NULL 2 2017-08-03 1111111 Book 2
1 2017-07-01 1 2017-07-02 12345 Book 1
2 2017-08-01 NULL NULL 67890 Book 3
SELECT
GROUP_CONCAT(so_id) so_id,
GROUP_CONCAT(so_date) so_date,
GROUP_CONCAT(po_id) po_id,
GROUP_CONCAT(po_date) po_date,
isbn,
dscr
FROM (
SELECT
hd.so_id so_id,
NULL so_date,
hd.id po_id,
hd.dt po_date,
bk.isbn,
it.dscr
FROM porders_hd hd,
porders_it it,
books bk
WHERE it.hd_id = hd.id
AND bk.isbn = it.isbn
AND kind = 2
UNION
SELECT
hd.id so_id,
hd.dt so_date,
NULL po_id,
NULL po_date,
bk.isbn,
it.dscr
FROM sorders_hd hd,
sorders_it it,
books bk
WHERE it.hd_id = hd.id
AND bk.isbn = it.isbn
AND kind = 1
) as table1
GROUP BY isbn, so_id, po_id
我尝试使用如下查询获取行:
so_id so_date po_id po_date isbn dscr
NULL NULL 2 2017-08-03 1111111 Book 2
1 2017-07-01 1 2017-07-02 12345 Book 1
2 2017-08-01 NULL NULL 67890 Book 3
SELECT
GROUP_CONCAT(so_id) so_id,
GROUP_CONCAT(so_date) so_date,
GROUP_CONCAT(po_id) po_id,
GROUP_CONCAT(po_date) po_date,
isbn,
dscr
FROM (
SELECT
hd.so_id so_id,
NULL so_date,
hd.id po_id,
hd.dt po_date,
bk.isbn,
it.dscr
FROM porders_hd hd,
porders_it it,
books bk
WHERE it.hd_id = hd.id
AND bk.isbn = it.isbn
AND kind = 2
UNION
SELECT
hd.id so_id,
hd.dt so_date,
NULL po_id,
NULL po_date,
bk.isbn,
it.dscr
FROM sorders_hd hd,
sorders_it it,
books bk
WHERE it.hd_id = hd.id
AND bk.isbn = it.isbn
AND kind = 1
) as table1
GROUP BY isbn, so_id, po_id
但由于缺少信息,我得到以下结果:
so_id so_date po_id po_date isbn dscr
NULL NULL 2 2017-08-03 1111111 Book 2
1 2017-07-01 NULL NULL 12345 Book 1
1 NULL 1 2017-07-02 12345 Book 1
2 2017-08-01 NULL NULL 67890 Book 3
有什么办法可以做到这一点吗?我想这就是你想要的,但我可以;t从代码中找出
kind
的角色。但这里有一个查询,用于为每个账簿获取关联的采购订单行项目,查找相应的so行项目,并连接标题行,以便日期可用。请注意,我的假设是,销售订单不能与相应的采购订单一起存在
SELECT books.isbn, books.descr, sorders_hd.id, sorders_hd.dt, porders_hd.id, porders_hd.dt
FROM book
join porders_it on porders_it.isbn = books.isbn
join porders_hd on porders_hd.id = porders_it.hd_id
left outer join sorders_it on sorders_it.hd_id=porders_hd.so_id and sorders_it.isbn = porders_it.isbn
left outer join sorders_hd on sorders_hd.id = sorders_it.hd_it
您可以规范化您的表,以便不需要重复descr,还可以在其他表中使用book.id而不是isbn。我想这是您想要的,但我可以;t从代码中找出
kind
的角色。但这里有一个查询,用于为每个账簿获取关联的采购订单行项目,查找相应的so行项目,并连接标题行,以便日期可用。请注意,我的假设是,销售订单不能与相应的采购订单一起存在
SELECT books.isbn, books.descr, sorders_hd.id, sorders_hd.dt, porders_hd.id, porders_hd.dt
FROM book
join porders_it on porders_it.isbn = books.isbn
join porders_hd on porders_hd.id = porders_it.hd_id
left outer join sorders_it on sorders_it.hd_id=porders_hd.so_id and sorders_it.isbn = porders_it.isbn
left outer join sorders_hd on sorders_hd.id = sorders_it.hd_it
您可以规范化您的表,这样就不需要重复descr,还可以在其他表中使用book.id而不是isbn。我添加了一个新答案,因为前面的答案和注释都是说明性的。基于上述讨论,这需要一个完整的外部连接,必须由mysql中的UNION ALL模拟(这可能是OP最初尝试的) 这是我的新代码,考虑到这一点:
SELECT sorders_hd.id as so_id, sorders_hd.dt as so_dt,
porders_hd.id as po_id, porders_hd.dt as po_dt,
books.isbn, porders_it.dscr
from books
left outer join porders_it on porders_it.isbn=books.isbn
join porders_hd on porders_hd.id=porders_it.hd_id
left outer join sorders_it on sorders_it.isbn=books.isbn and sorders_it.hd_id=porders_hd.so_id
left outer join sorders_hd on sorders_hd.id=sorders_it.hd_id
where books.kind=2
UNION ALL
SELECT sorders_hd.id as so_id, sorders_hd.dt as so_dt,
porders_hd.id as po_id, porders_hd.dt as po_dt,
books.isbn, sorders_it.dscr
from books
left outer join sorders_it on sorders_it.isbn=books.isbn
join sorders_hd on sorders_hd.id=sorders_it.hd_id
left outer join porders_it on porders_it.isbn=books.isbn
left outer join porders_hd on porders_hd.id=porders_it.hd_id and porders_hd.so_id=sorders_hd.id
where porders_hd.id is null and books.kind=1;
输出结果是:
so_id so_dt po_id po_dt isbn dscr
1 2017-07-01 1 2017-07-02 12345 Book 1
(null) (null) 2 2017-08-03 1111111 Book 2
2 2017-08-01 (null) (null) 67890 Book 2
看
“诀窍”是将union all与两个查询中的一个一起使用,不包括链接两侧的记录(以获取完整外部联接的“右侧”)
+1到OP提供DDL和样本数据
我同意数据模型可以被修改,也可以被规范化。当销售订单和采购订单匹配(其中一个被忽略)时,现有模型仍然存在至少重复账簿记录的问题。在我看来,一个改进是拥有一个主图书列表,并在porders_It和sorders_It中包含该表的id(或isbn,如果这是主键),并删除当前图书表。我添加一个新的答案,因为前面的答案和注释都是说明性的。基于上述讨论,这需要一个完整的外部连接,必须由mysql中的UNION ALL模拟(这可能是OP最初尝试的) 这是我的新代码,考虑到这一点:
SELECT sorders_hd.id as so_id, sorders_hd.dt as so_dt,
porders_hd.id as po_id, porders_hd.dt as po_dt,
books.isbn, porders_it.dscr
from books
left outer join porders_it on porders_it.isbn=books.isbn
join porders_hd on porders_hd.id=porders_it.hd_id
left outer join sorders_it on sorders_it.isbn=books.isbn and sorders_it.hd_id=porders_hd.so_id
left outer join sorders_hd on sorders_hd.id=sorders_it.hd_id
where books.kind=2
UNION ALL
SELECT sorders_hd.id as so_id, sorders_hd.dt as so_dt,
porders_hd.id as po_id, porders_hd.dt as po_dt,
books.isbn, sorders_it.dscr
from books
left outer join sorders_it on sorders_it.isbn=books.isbn
join sorders_hd on sorders_hd.id=sorders_it.hd_id
left outer join porders_it on porders_it.isbn=books.isbn
left outer join porders_hd on porders_hd.id=porders_it.hd_id and porders_hd.so_id=sorders_hd.id
where porders_hd.id is null and books.kind=1;
输出结果是:
so_id so_dt po_id po_dt isbn dscr
1 2017-07-01 1 2017-07-02 12345 Book 1
(null) (null) 2 2017-08-03 1111111 Book 2
2 2017-08-01 (null) (null) 67890 Book 2
看
“诀窍”是将union all与两个查询中的一个一起使用,不包括链接两侧的记录(以获取完整外部联接的“右侧”)
+1到OP提供DDL和样本数据
我同意数据模型可以被修改,也可以被规范化。当销售订单和采购订单匹配(其中一个被忽略)时,现有模型仍然存在至少重复账簿记录的问题。在我看来,一个改进是拥有一个主图书列表,并将该表中的id(或isbn,如果这是主键)包含在porders_It和sorders_It中,并删除当前的图书表。我非常困惑,在queryHi krokodilko的末尾添加isbn分组,descr。非常快-谢谢:-)如果为同一ISBN下新的销售订单,结果不是预期的:-(将以下行添加到书籍中:5 12345 3 1添加排序者hd行:3 2018-08-05 5和排序者U it行:您将在一行中获得所有12345交易:-(我也完全糊涂了。你真的应该整理你的数据模型。每花一分钟设计一个干净的数据库,你就可以节省10到28分钟,而不会在将来遇到麻烦。一些不合理之处:你怎么能卖掉第二本买来的书(链接到so),当您订购3件,但售出1件1件时会发生什么?当so/po表中的一行已经告诉您它是否为so/po时,
books
中的kind
如何表示它是否为so/po?对于您当前的问题:您需要加入so和po(可能在po中使用您的so id,尽管如上所述,它并不总是有效)。我很困惑。在queryHi krokodilko的末尾添加按ISBN分组。非常快-谢谢:-)如果为同一ISBN下新的销售订单,结果不是预期的:-(将以下行添加到账簿中:5 12345 3 1添加排序者?行:3 2018-08-05 5并将其添加到排序者?行:您将在一行中获得所有12345交易:-(我也完全糊涂了。你真的应该整理你的数据模型。每花一分钟设计一个干净的数据库,你就可以节省10到28分钟,而不会在将来遇到麻烦。一些不合理之处:你怎么能卖掉第二本买来的书(链接到so),当您订购3件,但售出1件1件时会发生什么?当so/po表中的一行已经告诉您它是否为so/po时,books
中的kind
如何表示它是否为so/po?对于您当前的问题:您需要加入so和po(可能在po中使用您的so id,尽管如上所述,它并不总是有效).Hi RichGoldMD,谢谢您的回答。种类字段声明交易种类:1表示SO,2表示PO。此外,我无法规范化SO和PO dscr,因为当客户订购时,dscr可能不同,而您从供应商订购时:-(您的查询将丢失“孤立”)