Mysql 我的想法是错误的

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

我有以下场景:有一个带书籍的表和两对带销售订单和采购订单事务的表(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 (`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可能不同,而您从供应商订购时:-(您的查询将丢失“孤立”)